diff options
731 files changed, 25249 insertions, 8292 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index b37fce7002..f5874744b5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -27,6 +27,13 @@ env: # Global defaults # The above machine types are matched to each task by their label. Refer to the # Cirrus CI docs for more details. # +# When a contributor maintains a fork of the repo, any pull request they make +# to their own fork, or to the main repository, will trigger two CI runs: +# one for the branch push and one for the pull request. +# This can be avoided by setting SKIP_BRANCH_PUSH=true as a custom env variable +# in Cirrus repository settings, accessible from +# https://cirrus-ci.com/github/my-organization/my-repository +# # On machines that are persisted between CI jobs, RESTART_CI_DOCKER_BEFORE_RUN=1 # ensures that previous containers and artifacts are cleared before each run. # This requires installing Podman instead of Docker. @@ -59,7 +66,10 @@ env: # Global defaults # https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks filter_template: &FILTER_TEMPLATE - skip: $CIRRUS_REPO_FULL_NAME == "bitcoin-core/gui" && $CIRRUS_PR == "" # No need to run on the read-only mirror, unless it is a PR. https://cirrus-ci.org/guide/writing-tasks/#conditional-task-execution + # Allow forks to specify SKIP_BRANCH_PUSH=true and skip CI runs when a branch is pushed, + # but still run CI when a PR is created. + # https://cirrus-ci.org/guide/writing-tasks/#conditional-task-execution + skip: $SKIP_BRANCH_PUSH == "true" && $CIRRUS_PR == "" stateful: false # https://cirrus-ci.org/guide/writing-tasks/#stateful-tasks base_template: &BASE_TEMPLATE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54795332e8..7961c3c900 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,13 @@ jobs: # and the ^ prefix is used to exclude these parents and all their # ancestors from the rev-list output as described in: # https://git-scm.com/docs/git-rev-list - echo "TEST_BASE=$(git rev-list -n$((${{ env.MAX_COUNT }} + 1)) --reverse HEAD ^$(git rev-list -n1 --merges HEAD)^@ | head -1)" >> "$GITHUB_ENV" + MERGE_BASE=$(git rev-list -n1 --merges HEAD) + EXCLUDE_MERGE_BASE_ANCESTORS= + # MERGE_BASE can be empty due to limited fetch-depth + if test -n "$MERGE_BASE"; then + EXCLUDE_MERGE_BASE_ANCESTORS=^${MERGE_BASE}^@ + fi + echo "TEST_BASE=$(git rev-list -n$((${{ env.MAX_COUNT }} + 1)) --reverse HEAD $EXCLUDE_MERGE_BASE_ANCESTORS | head -1)" >> "$GITHUB_ENV" - run: | sudo apt-get update sudo apt-get install clang ccache build-essential libtool autotools-dev automake pkg-config bsdmainutils python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libnatpmp-dev qtbase5-dev qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y @@ -66,7 +72,7 @@ jobs: run: | # Run tests on commits after the last merge commit and before the PR head commit # Use clang++, because it is a bit faster and uses less memory than g++ - git rebase --exec "echo Running test-one-commit on \$( git log -1 ) && ./autogen.sh && CC=clang CXX=clang++ ./configure && make clean && make -j $(nproc) check && ./test/functional/test_runner.py -j $(( $(nproc) * 2 ))" ${{ env.TEST_BASE }} + git rebase --exec "echo Running test-one-commit on \$( git log -1 ) && ./autogen.sh && CC=clang CXX=clang++ ./configure --with-incompatible-bdb && make clean && make -j $(nproc) check && ./test/functional/test_runner.py -j $(( $(nproc) * 2 ))" ${{ env.TEST_BASE }} macos-native-x86_64: name: 'macOS 13 native, x86_64, no depends, sqlite only, gui' @@ -98,8 +104,8 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 run: | # A workaround for "The `brew link` step did not complete successfully" error. - brew install python@3 || brew link --overwrite python@3 - brew install automake libtool pkg-config gnu-getopt ccache boost libevent miniupnpc libnatpmp zeromq qt@5 qrencode + brew install --quiet python@3 || brew link --overwrite python@3 + brew install --quiet automake libtool pkg-config gnu-getopt ccache boost libevent miniupnpc libnatpmp zeromq qt@5 qrencode - name: Set Ccache directory run: echo "CCACHE_DIR=${RUNNER_TEMP}/ccache_dir" >> "$GITHUB_ENV" diff --git a/.tx/config b/.tx/config index 0192284a82..02d80379d1 100644 --- a/.tx/config +++ b/.tx/config @@ -1,7 +1,7 @@ [main] host = https://www.transifex.com -[o:bitcoin:p:bitcoin:r:qt-translation-027x] +[o:bitcoin:p:bitcoin:r:qt-translation-028x] file_filter = src/qt/locale/bitcoin_<lang>.xlf source_file = src/qt/locale/bitcoin_en.xlf source_lang = en diff --git a/Makefile.am b/Makefile.am index 2ff6dd0a11..b746299a42 100644 --- a/Makefile.am +++ b/Makefile.am @@ -334,14 +334,14 @@ clean-local: clean-docs test-security-check: if TARGET_DARWIN - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_MACHO + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_MACHO endif if TARGET_WINDOWS - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_PE + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_PE + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_PE endif if TARGET_LINUX - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF - $(AM_V_at) CC='$(CC)' CFLAGS='$(CFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-security-check.py TestSecurityChecks.test_ELF + $(AM_V_at) CXX='$(CXX)' CXXFLAGS='$(CXXFLAGS)' CPPFLAGS='$(CPPFLAGS)' LDFLAGS='$(LDFLAGS)' $(PYTHON) $(top_srcdir)/contrib/devtools/test-symbol-check.py TestSymbolChecks.test_ELF endif diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index b87c38a6ab..7498127860 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -123,7 +123,6 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi fi - AC_DEFINE([QT_STATICPLUGIN], [1], [Define this symbol if qt plugins are static]) _BITCOIN_QT_CHECK_STATIC_PLUGIN([QMinimalIntegrationPlugin], [-lqminimal]) AC_DEFINE([QT_QPA_PLATFORM_MINIMAL], [1], [Define this symbol if the minimal qt platform exists]) if test "$TARGET_OS" = "windows"; then diff --git a/build_msvc/bitcoin_config.h.in b/build_msvc/bitcoin_config.h.in index 2d6df92286..b0238c9112 100644 --- a/build_msvc/bitcoin_config.h.in +++ b/build_msvc/bitcoin_config.h.in @@ -49,9 +49,6 @@ */ #define HAVE_DECL_SETSID 0 -/* Define if the dllexport attribute is supported. */ -#define HAVE_DLLEXPORT_ATTRIBUTE 1 - /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "https://github.com/bitcoin/bitcoin/issues" @@ -73,9 +70,6 @@ /* Define this symbol if the qt platform is windows */ #define QT_QPA_PLATFORM_WINDOWS 1 -/* Define this symbol if qt plugins are static */ -#define QT_STATICPLUGIN 1 - /* Windows Universal Platform constraints */ #if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) /* Either a desktop application without API restrictions, or and older system diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh index 87e3a8fa9b..acec2f32e9 100755 --- a/ci/lint/04_install.sh +++ b/ci/lint/04_install.sh @@ -1,12 +1,14 @@ #!/usr/bin/env bash # -# Copyright (c) 2018-2022 The Bitcoin Core developers +# Copyright (c) 2018-present 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 -export PATH=$PWD/ci/retry:$PATH +export CI_RETRY_EXE="/ci_retry --" + +pushd "/" ${CI_RETRY_EXE} apt-get update # Lint dependencies: @@ -19,7 +21,7 @@ ${CI_RETRY_EXE} apt-get install -y automake pkg-config libtool curl xz-utils git PYTHON_PATH="/python_build" if [ ! -d "${PYTHON_PATH}/bin" ]; then ( - ${CI_RETRY_EXE} git clone https://github.com/pyenv/pyenv.git + ${CI_RETRY_EXE} git clone --depth=1 https://github.com/pyenv/pyenv.git cd pyenv/plugins/python-build || exit 1 ./install.sh ) @@ -28,7 +30,7 @@ if [ ! -d "${PYTHON_PATH}/bin" ]; then 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 "./.python-version")" "${PYTHON_PATH}" + env CC=clang python-build "$(cat "/.python-version")" "${PYTHON_PATH}" fi export PATH="${PYTHON_PATH}/bin:${PATH}" command -v python3 @@ -38,7 +40,7 @@ export LINT_RUNNER_PATH="/lint_test_runner" if [ ! -d "${LINT_RUNNER_PATH}" ]; then ${CI_RETRY_EXE} apt-get install -y cargo ( - cd ./test/lint/test_runner || exit 1 + cd "/test/lint/test_runner" || exit 1 cargo build mkdir -p "${LINT_RUNNER_PATH}" mv target/debug/test_runner "${LINT_RUNNER_PATH}" @@ -51,6 +53,7 @@ ${CI_RETRY_EXE} pip3 install \ lief==0.13.2 \ mypy==1.4.1 \ pyzmq==25.1.0 \ + ruff==0.5.5 \ vulture==2.6 SHELLCHECK_VERSION=v0.8.0 @@ -58,7 +61,9 @@ curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_ tar --xz -xf - --directory /tmp/ mv "/tmp/shellcheck-${SHELLCHECK_VERSION}/shellcheck" /usr/bin/ -MLC_VERSION=v0.16.3 +MLC_VERSION=v0.18.0 MLC_BIN=mlc-x86_64-linux curl -sL "https://github.com/becheran/mlc/releases/download/${MLC_VERSION}/${MLC_BIN}" -o "/usr/bin/mlc" chmod +x /usr/bin/mlc + +popd || exit diff --git a/ci/lint_imagefile b/ci/lint_imagefile index d32b35b19d..0e7ede5204 100644 --- a/ci/lint_imagefile +++ b/ci/lint_imagefile @@ -4,11 +4,12 @@ # See test/lint/README.md for usage. -FROM debian:bookworm +FROM docker.io/debian:bookworm ENV DEBIAN_FRONTEND=noninteractive ENV LC_ALL=C.UTF-8 +COPY ./ci/retry/retry /ci_retry COPY ./.python-version /.python-version COPY ./ci/lint/container-entrypoint.sh /entrypoint.sh COPY ./ci/lint/04_install.sh /install.sh diff --git a/ci/lint_run_all.sh b/ci/lint_run_all.sh index b56ee0d303..c57261d21a 100755 --- a/ci/lint_run_all.sh +++ b/ci/lint_run_all.sh @@ -1,12 +1,17 @@ #!/usr/bin/env bash # -# Copyright (c) 2019-2020 The Bitcoin Core developers +# Copyright (c) 2019-present 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 -set -o errexit; source ./ci/test/00_setup_env.sh +# Only used in .cirrus.yml. Refer to test/lint/README.md on how to run locally. + +cp "./ci/retry/retry" "/ci_retry" +cp "./.python-version" "/.python-version" +mkdir --parents "/test/lint" +cp --recursive "./test/lint/test_runner" "/test/lint/" set -o errexit; source ./ci/lint/04_install.sh set -o errexit ./ci/lint/06_script.sh diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh index 23d9180f96..9ab08fb4a3 100755 --- a/ci/test/00_setup_env_native_asan.sh +++ b/ci/test/00_setup_env_native_asan.sh @@ -19,7 +19,7 @@ else fi export CONTAINER_NAME=ci_native_asan -export PACKAGES="systemtap-sdt-dev clang-18 llvm-18 libclang-rt-18-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}" +export PACKAGES="systemtap-sdt-dev clang-18 llvm-18 libclang-rt-18-dev python3-zmq qtbase5-dev qttools5-dev qttools5-dev-tools libevent-dev libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}" export NO_DEPENDS=1 export GOAL="install" export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 \ diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh index 6425120afb..49660aac0c 100755 --- a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh +++ b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh @@ -7,9 +7,9 @@ export LC_ALL=C.UTF-8 export CONTAINER_NAME=ci_native_nowallet_libbitcoinkernel -export CI_IMAGE_NAME_TAG="docker.io/ubuntu:22.04" -# Use minimum supported python3.9 (or best-effort 3.10) and clang-15, see doc/dependencies.md -export PACKAGES="python3-zmq clang-15 llvm-15 libc++abi-15-dev libc++-15-dev" -export DEP_OPTS="NO_WALLET=1 CC=clang-15 CXX='clang++-15 -stdlib=libc++'" +export CI_IMAGE_NAME_TAG="docker.io/debian:bullseye" +# Use minimum supported python3.9 and clang-16, see doc/dependencies.md +export PACKAGES="python3-zmq clang-16 llvm-16 libc++abi-16-dev libc++-16-dev" +export DEP_OPTS="NO_WALLET=1 CC=clang-16 CXX='clang++-16 -stdlib=libc++'" export GOAL="install" export BITCOIN_CONFIG="--enable-reduce-exports --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh index 3fcaa8c6c6..5bfbb4cbf1 100755 --- a/ci/test/00_setup_env_native_tsan.sh +++ b/ci/test/00_setup_env_native_tsan.sh @@ -11,4 +11,4 @@ export CI_IMAGE_NAME_TAG="docker.io/ubuntu:24.04" export PACKAGES="clang-18 llvm-18 libclang-rt-18-dev libc++abi-18-dev libc++-18-dev python3-zmq" export DEP_OPTS="CC=clang-18 CXX='clang++-18 -stdlib=libc++'" export GOAL="install" -export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' --with-sanitizers=thread" +export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES' --with-sanitizers=thread" diff --git a/configure.ac b/configure.ac index af0d1d1505..eaecd1c7e4 100644 --- a/configure.ac +++ b/configure.ac @@ -482,11 +482,12 @@ TEMP_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$SSE41_CXXFLAGS $CXXFLAGS" AC_MSG_CHECKING([for SSE4.1 intrinsics]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <stdint.h> #include <immintrin.h> ]],[[ - __m128i l = _mm_set1_epi32(0); - return _mm_extract_epi32(l, 3); + __m128i a = _mm_set1_epi32(0); + __m128i b = _mm_set1_epi32(1); + __m128i r = _mm_blend_epi16(a, b, 0xFF); + return _mm_extract_epi32(r, 3); ]])], [ AC_MSG_RESULT([yes]); enable_sse41=yes; AC_DEFINE([ENABLE_SSE41], [1], [Define this symbol to build code that uses SSE4.1 intrinsics]) ], [ AC_MSG_RESULT([no])] @@ -942,35 +943,6 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [ AC_MSG_RESULT([no])] ) -AC_MSG_CHECKING([for default visibility attribute]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - int foo(void) __attribute__((visibility("default"))); - int main(){} - ])], - [ - AC_DEFINE([HAVE_DEFAULT_VISIBILITY_ATTRIBUTE], [1], [Define if the visibility attribute is supported.]) - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - if test "$use_reduce_exports" = "yes"; then - AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduce-exports.]) - fi - ] -) - -AC_MSG_CHECKING([for dllexport attribute]) -AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - __declspec(dllexport) int foo(void); - int main(){} - ])], - [ - AC_DEFINE([HAVE_DLLEXPORT_ATTRIBUTE], [1], [Define if the dllexport attribute is supported.]) - AC_MSG_RESULT([yes]) - ], - [AC_MSG_RESULT([no])] -) - dnl Check for different ways of gathering OS randomness AC_MSG_CHECKING([for Linux getrandom function]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -1317,6 +1289,7 @@ if test "$use_reduce_exports" = "yes"; then AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [CORE_CXXFLAGS="$CORE_CXXFLAGS -fvisibility=hidden"], [AC_MSG_ERROR([Cannot set hidden symbol visibility. Use --disable-reduce-exports.])], [$CXXFLAG_WERROR]) AX_CHECK_LINK_FLAG([-Wl,--exclude-libs,ALL], [RELDFLAGS="-Wl,--exclude-libs,ALL"], [], [$LDFLAG_WERROR]) + AX_CHECK_LINK_FLAG([-Wl,-no_exported_symbols], [LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -Wl,-no_exported_symbols"], [], [$LDFLAG_WERROR]) fi if test "$use_tests" = "yes"; then @@ -1720,7 +1693,7 @@ CPPFLAGS="$CPPFLAGS_TEMP" if test -n "$use_sanitizers"; then export SECP_CFLAGS="$SECP_CFLAGS $SANITIZER_CFLAGS" fi -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-ecmult-gen-kb=86 --enable-benchmark=no --enable-module-recovery --disable-module-ecdh" +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/asmap/asmap-tool.py b/contrib/asmap/asmap-tool.py index 09c28725e4..33a380a2e7 100755 --- a/contrib/asmap/asmap-tool.py +++ b/contrib/asmap/asmap-tool.py @@ -6,7 +6,9 @@ import argparse import sys import ipaddress +import json import math +from collections import defaultdict import asmap @@ -113,6 +115,18 @@ def main(): parser_diff.add_argument('infile2', type=argparse.FileType('rb'), help="second file to compare (text or binary)") + parser_diff_addrs = subparsers.add_parser("diff_addrs", + help="compute difference between two asmap files for a set of addresses") + parser_diff_addrs.add_argument('-s', '--show-addresses', dest="show_addresses", default=False, action="store_true", + help="include reassigned addresses in the output") + parser_diff_addrs.add_argument("infile1", type=argparse.FileType("rb"), + help="first file to compare (text or binary)") + parser_diff_addrs.add_argument("infile2", type=argparse.FileType("rb"), + help="second file to compare (text or binary)") + parser_diff_addrs.add_argument("addrs_file", type=argparse.FileType("r"), + help="address file containing getnodeaddresses output to use in the comparison " + "(make sure to set the count parameter to zero to get all node addresses, " + "e.g. 'bitcoin-cli getnodeaddresses 0 > addrs.json')") args = parser.parse_args() if args.subcommand is None: parser.print_help() @@ -148,6 +162,33 @@ def main(): f"# {ipv4_changed}{ipv4_change_str} IPv4 addresses changed; " f"{ipv6_changed}{ipv6_change_str} IPv6 addresses changed" ) + elif args.subcommand == "diff_addrs": + state1 = load_file(args.infile1) + state2 = load_file(args.infile2) + address_info = json.load(args.addrs_file) + addrs = {a["address"] for a in address_info if a["network"] in ["ipv4", "ipv6"]} + reassignments = defaultdict(list) + for addr in addrs: + net = ipaddress.ip_network(addr) + prefix = asmap.net_to_prefix(net) + old_asn = state1.lookup(prefix) + new_asn = state2.lookup(prefix) + if new_asn != old_asn: + reassignments[(old_asn, new_asn)].append(addr) + reassignments = sorted(reassignments.items(), key=lambda item: len(item[1]), reverse=True) + num_reassignment_type = defaultdict(int) + for (old_asn, new_asn), reassigned_addrs in reassignments: + num_reassigned = len(reassigned_addrs) + num_reassignment_type[(bool(old_asn), bool(new_asn))] += num_reassigned + old_asn_str = f"AS{old_asn}" if old_asn else "unassigned" + new_asn_str = f"AS{new_asn}" if new_asn else "unassigned" + opt = ": " + ", ".join(reassigned_addrs) if args.show_addresses else "" + print(f"{num_reassigned} address(es) reassigned from {old_asn_str} to {new_asn_str}{opt}") + num_reassignments = sum(len(addrs) for _, addrs in reassignments) + share = num_reassignments / len(addrs) if len(addrs) > 0 else 0 + print(f"Summary: {num_reassignments:,} ({share:.2%}) of {len(addrs):,} addresses were reassigned " + f"(migrations={num_reassignment_type[True, True]}, assignments={num_reassignment_type[False, True]}, " + f"unassignments={num_reassignment_type[True, False]})") else: parser.print_help() sys.exit("No command provided.") diff --git a/contrib/completions/bash/bitcoin-cli.bash b/contrib/completions/bash/bitcoin-cli.bash index 89e01bc09a..b04fdbcb0e 100644 --- a/contrib/completions/bash/bitcoin-cli.bash +++ b/contrib/completions/bash/bitcoin-cli.bash @@ -9,7 +9,7 @@ _bitcoin_rpc() { local rpcargs=() for i in ${COMP_LINE}; do case "$i" in - -conf=*|-datadir=*|-regtest|-rpc*|-testnet) + -conf=*|-datadir=*|-regtest|-rpc*|-testnet|-testnet4) rpcargs=( "${rpcargs[@]}" "$i" ) ;; esac diff --git a/contrib/devtools/bitcoin-tidy/CMakeLists.txt b/contrib/devtools/bitcoin-tidy/CMakeLists.txt index 1260c71423..95345b4782 100644 --- a/contrib/devtools/bitcoin-tidy/CMakeLists.txt +++ b/contrib/devtools/bitcoin-tidy/CMakeLists.txt @@ -25,7 +25,7 @@ find_program(CLANG_TIDY_EXE NAMES "clang-tidy-${LLVM_VERSION_MAJOR}" "clang-tidy message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}") -add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp logprintf.cpp) +add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp logprintf.cpp nontrivial-threadlocal.cpp) target_include_directories(bitcoin-tidy SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS}) # Disable RTTI and exceptions as necessary @@ -58,7 +58,7 @@ else() endif() # Create a dummy library that runs clang-tidy tests as a side-effect of building -add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL example_logprintf.cpp) +add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL example_logprintf.cpp example_nontrivial-threadlocal.cpp) add_dependencies(bitcoin-tidy-tests bitcoin-tidy) set_target_properties(bitcoin-tidy-tests PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}") diff --git a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp index 0f34d37793..1ef4494973 100644 --- a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp +++ b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "logprintf.h" +#include "nontrivial-threadlocal.h" #include <clang-tidy/ClangTidyModule.h> #include <clang-tidy/ClangTidyModuleRegistry.h> @@ -13,6 +14,7 @@ public: void addCheckFactories(clang::tidy::ClangTidyCheckFactories& CheckFactories) override { CheckFactories.registerCheck<bitcoin::LogPrintfCheck>("bitcoin-unterminated-logprintf"); + CheckFactories.registerCheck<bitcoin::NonTrivialThreadLocal>("bitcoin-nontrivial-threadlocal"); } }; diff --git a/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp b/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp new file mode 100644 index 0000000000..2b74df5d0e --- /dev/null +++ b/contrib/devtools/bitcoin-tidy/example_nontrivial-threadlocal.cpp @@ -0,0 +1,2 @@ +#include <string> +thread_local std::string foo; diff --git a/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp new file mode 100644 index 0000000000..d2bc78a31b --- /dev/null +++ b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Bitcoin Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "nontrivial-threadlocal.h" + +#include <clang/AST/ASTContext.h> +#include <clang/ASTMatchers/ASTMatchFinder.h> + + +// Copied from clang-tidy's UnusedRaiiCheck +namespace { +AST_MATCHER(clang::CXXRecordDecl, hasNonTrivialDestructor) { + // TODO: If the dtor is there but empty we don't want to warn either. + return Node.hasDefinition() && Node.hasNonTrivialDestructor(); +} +} // namespace + +namespace bitcoin { + +void NonTrivialThreadLocal::registerMatchers(clang::ast_matchers::MatchFinder* finder) +{ + using namespace clang::ast_matchers; + + /* + thread_local std::string foo; + */ + + finder->addMatcher( + varDecl( + hasThreadStorageDuration(), + hasType(hasCanonicalType(recordType(hasDeclaration(cxxRecordDecl(hasNonTrivialDestructor()))))) + ).bind("nontrivial_threadlocal"), + this); +} + +void NonTrivialThreadLocal::check(const clang::ast_matchers::MatchFinder::MatchResult& Result) +{ + if (const clang::VarDecl* var = Result.Nodes.getNodeAs<clang::VarDecl>("nontrivial_threadlocal")) { + const auto user_diag = diag(var->getBeginLoc(), "Variable with non-trivial destructor cannot be thread_local."); + } +} + +} // namespace bitcoin diff --git a/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h new file mode 100644 index 0000000000..c853073467 --- /dev/null +++ b/contrib/devtools/bitcoin-tidy/nontrivial-threadlocal.h @@ -0,0 +1,29 @@ +// Copyright (c) 2023 Bitcoin Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef NONTRIVIAL_THREADLOCAL_CHECK_H +#define NONTRIVIAL_THREADLOCAL_CHECK_H + +#include <clang-tidy/ClangTidyCheck.h> + +namespace bitcoin { + +// Warn about any thread_local variable with a non-trivial destructor. +class NonTrivialThreadLocal final : public clang::tidy::ClangTidyCheck +{ +public: + NonTrivialThreadLocal(clang::StringRef Name, clang::tidy::ClangTidyContext* Context) + : clang::tidy::ClangTidyCheck(Name, Context) {} + + bool isLanguageVersionSupported(const clang::LangOptions& LangOpts) const override + { + return LangOpts.CPlusPlus; + } + void registerMatchers(clang::ast_matchers::MatchFinder* Finder) override; + void check(const clang::ast_matchers::MatchFinder::MatchResult& Result) override; +}; + +} // namespace bitcoin + +#endif // NONTRIVIAL_THREADLOCAL_CHECK_H diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 3dddffe324..3c98ee7b20 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -19,7 +19,6 @@ EXCLUDE = [ 'src/qt/bitcoinstrings.cpp', 'src/chainparamsseeds.h', # other external copyrights: - 'src/reverse_iterator.h', 'src/test/fuzz/FuzzedDataProvider.h', 'src/tinyformat.h', 'src/bench/nanobench.h', diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index f57e9abfec..46f9ee915f 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -38,13 +38,13 @@ def check_ELF_RELRO(binary) -> bool: return have_gnu_relro and have_bindnow -def check_ELF_Canary(binary) -> bool: +def check_ELF_CANARY(binary) -> bool: ''' Check for use of stack canary ''' return binary.has_symbol('__stack_chk_fail') -def check_ELF_separate_code(binary): +def check_ELF_SEPARATE_CODE(binary): ''' Check that sections are appropriately separated in virtual memory, based on their permissions. This checks for missing -Wl,-z,separate-code @@ -105,7 +105,7 @@ def check_ELF_separate_code(binary): return False return True -def check_ELF_control_flow(binary) -> bool: +def check_ELF_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -130,7 +130,7 @@ def check_PE_RELOC_SECTION(binary) -> bool: '''Check for a reloc section. This is required for functional ASLR.''' return binary.has_relocations -def check_PE_control_flow(binary) -> bool: +def check_PE_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -145,7 +145,7 @@ def check_PE_control_flow(binary) -> bool: return True return False -def check_PE_Canary(binary) -> bool: +def check_PE_CANARY(binary) -> bool: ''' Check for use of stack canary ''' @@ -163,7 +163,7 @@ def check_MACHO_FIXUP_CHAINS(binary) -> bool: ''' return binary.has_dyld_chained_fixups -def check_MACHO_Canary(binary) -> bool: +def check_MACHO_CANARY(binary) -> bool: ''' Check for use of stack canary ''' @@ -182,7 +182,7 @@ def check_NX(binary) -> bool: ''' return binary.has_nx -def check_MACHO_control_flow(binary) -> bool: +def check_MACHO_CONTROL_FLOW(binary) -> bool: ''' Check for control flow instrumentation ''' @@ -192,7 +192,7 @@ def check_MACHO_control_flow(binary) -> bool: return True return False -def check_MACHO_branch_protection(binary) -> bool: +def check_MACHO_BRANCH_PROTECTION(binary) -> bool: ''' Check for branch protection instrumentation ''' @@ -206,8 +206,8 @@ BASE_ELF = [ ('PIE', check_PIE), ('NX', check_NX), ('RELRO', check_ELF_RELRO), - ('Canary', check_ELF_Canary), - ('separate_code', check_ELF_separate_code), + ('CANARY', check_ELF_CANARY), + ('SEPARATE_CODE', check_ELF_SEPARATE_CODE), ] BASE_PE = [ @@ -216,19 +216,19 @@ BASE_PE = [ ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_NX), ('RELOC_SECTION', check_PE_RELOC_SECTION), - ('CONTROL_FLOW', check_PE_control_flow), - ('Canary', check_PE_Canary), + ('CONTROL_FLOW', check_PE_CONTROL_FLOW), + ('CANARY', check_PE_CANARY), ] BASE_MACHO = [ ('NOUNDEFS', check_MACHO_NOUNDEFS), - ('Canary', check_MACHO_Canary), + ('CANARY', check_MACHO_CANARY), ('FIXUP_CHAINS', check_MACHO_FIXUP_CHAINS), ] CHECKS = { lief.EXE_FORMATS.ELF: { - lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_control_flow)], + lief.ARCHITECTURES.X86: BASE_ELF + [('CONTROL_FLOW', check_ELF_CONTROL_FLOW)], lief.ARCHITECTURES.ARM: BASE_ELF, lief.ARCHITECTURES.ARM64: BASE_ELF, lief.ARCHITECTURES.PPC: BASE_ELF, @@ -240,39 +240,24 @@ CHECKS = { lief.EXE_FORMATS.MACHO: { lief.ARCHITECTURES.X86: BASE_MACHO + [('PIE', check_PIE), ('NX', check_NX), - ('CONTROL_FLOW', check_MACHO_control_flow)], - lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_branch_protection)], + ('CONTROL_FLOW', check_MACHO_CONTROL_FLOW)], + lief.ARCHITECTURES.ARM64: BASE_MACHO + [('BRANCH_PROTECTION', check_MACHO_BRANCH_PROTECTION)], } } if __name__ == '__main__': retval: int = 0 for filename in sys.argv[1:]: - try: - binary = lief.parse(filename) - etype = binary.format - arch = binary.abstract.header.architecture - binary.concrete - - if etype == lief.EXE_FORMATS.UNKNOWN: - print(f'{filename}: unknown executable format') - retval = 1 - continue - - if arch == lief.ARCHITECTURES.NONE: - print(f'{filename}: unknown architecture') - retval = 1 - continue - - failed: list[str] = [] - for (name, func) in CHECKS[etype][arch]: - if not func(binary): - failed.append(name) - if failed: - print(f'{filename}: failed {" ".join(failed)}') - retval = 1 - except IOError: - print(f'{filename}: cannot open') + binary = lief.parse(filename) + etype = binary.format + arch = binary.abstract.header.architecture + binary.concrete + + failed: list[str] = [] + for (name, func) in CHECKS[etype][arch]: + if not func(binary): + failed.append(name) + if failed: + print(f'{filename}: failed {" ".join(failed)}') retval = 1 sys.exit(retval) - diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index c4e6bc81e1..1722c7d290 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -245,7 +245,7 @@ def check_MACHO_sdk(binary) -> bool: return False def check_MACHO_lld(binary) -> bool: - if binary.build_version.tools[0].version == [18, 1, 6]: + if binary.build_version.tools[0].version == [18, 1, 8]: return True return False @@ -299,22 +299,14 @@ lief.EXE_FORMATS.PE: [ if __name__ == '__main__': retval: int = 0 for filename in sys.argv[1:]: - try: - binary = lief.parse(filename) - etype = binary.format - if etype == lief.EXE_FORMATS.UNKNOWN: - print(f'{filename}: unknown executable format') - retval = 1 - continue - - failed: list[str] = [] - for (name, func) in CHECKS[etype]: - if not func(binary): - failed.append(name) - if failed: - print(f'{filename}: failed {" ".join(failed)}') - retval = 1 - except IOError: - print(f'{filename}: cannot open') + binary = lief.parse(filename) + etype = binary.format + + failed: list[str] = [] + for (name, func) in CHECKS[etype]: + if not func(binary): + failed.append(name) + if failed: + print(f'{filename}: failed {" ".join(failed)}') retval = 1 sys.exit(retval) diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 7bfd4d98da..4bec6bfe7c 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -15,10 +15,10 @@ from utils import determine_wellknown_cmd def write_testcode(filename): with open(filename, 'w', encoding="utf8") as f: f.write(''' - #include <stdio.h> + #include <cstdio> int main() { - printf("the quick brown fox jumps over the lazy god\\n"); + std::printf("the quick brown fox jumps over the lazy god\\n"); return 0; } ''') @@ -34,17 +34,17 @@ def env_flags() -> list[str]: # See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for # reference. flags: list[str] = [] - for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']: + for var in ['CXXFLAGS', 'CPPFLAGS', 'LDFLAGS']: flags += filter(None, os.environ.get(var, '').split(' ')) return flags -def call_security_check(cc: str, source: str, executable: str, options) -> tuple: - subprocess.run([*cc,source,'-o',executable] + env_flags() + options, check=True) +def call_security_check(cxx: str, source: str, executable: str, options) -> tuple: + subprocess.run([*cxx,source,'-o',executable] + env_flags() + options, check=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): - subprocess.run([*cc, source, '-o', executable] + env_flags(), check=True) +def get_arch(cxx, source, executable): + subprocess.run([*cxx, source, '-o', executable] + env_flags(), check=True) binary = lief.parse(executable) arch = binary.abstract.header.architecture os.remove(executable) @@ -52,95 +52,72 @@ def get_arch(cc, source, executable): class TestSecurityChecks(unittest.TestCase): def test_ELF(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1' - cc = determine_wellknown_cmd('CC', 'gcc') + cxx = determine_wellknown_cmd('CXX', 'g++') write_testcode(source) - arch = get_arch(cc, source, executable) + arch = get_arch(cxx, source, executable) if arch == lief.ARCHITECTURES.X86: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), - (1, executable+': failed separate_code CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full']), - (0, '')) + pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code', '-fcf-protection=full'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) else: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE NX RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-no-pie','-fno-PIE', '-Wl,-z,separate-code']), - (1, executable+': failed PIE RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-znorelro','-pie','-fPIE', '-Wl,-z,separate-code']), - (1, executable+': failed RELRO')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,noseparate-code']), - (1, executable+': failed separate_code')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE', '-Wl,-z,separate-code']), - (0, '')) + pass_flags = ['-Wl,-znoexecstack', '-Wl,-zrelro', '-Wl,-z,now', '-pie', '-fPIE', '-Wl,-z,separate-code'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-zexecstack']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-no-pie','-fno-PIE']), (1, executable + ': failed PIE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-znorelro']), (1, executable + ': failed RELRO')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-z,noseparate-code']), (1, executable + ': failed SEPARATE_CODE')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) def test_PE(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1.exe' - cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') + cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++') 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','-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','-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','-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','-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','-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','-fstack-protector-all', '-lssp']), - (0, '')) + pass_flags = ['-Wl,--nxcompat', '-Wl,--enable-reloc-section', '-Wl,--dynamicbase', '-Wl,--high-entropy-va', '-pie', '-fPIE', '-fcf-protection=full', '-fstack-protector-all', '-lssp'] + + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + # https://github.com/lief-project/LIEF/issues/1076 - in future, we could test this individually. + # self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-reloc-section']), (1, executable + ': failed RELOC_SECTION')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-nxcompat']), (1, executable + ': failed NX')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-dynamicbase']), (1, executable + ': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA')) # -pie -fPIE does nothing without --dynamicbase + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,--disable-high-entropy-va']), (1, executable + ': failed HIGH_ENTROPY_VA')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) def test_MACHO(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1' - cc = determine_wellknown_cmd('CC', 'clang') + cxx = determine_wellknown_cmd('CXX', 'clang++') write_testcode(source) - arch = get_arch(cc, source, executable) + arch = get_arch(cxx, source, executable) if arch == lief.ARCHITECTURES.X86: - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']), - (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS PIE CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains']), - (1, executable+': failed NOUNDEFS Canary CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains']), - (1, executable+': failed NOUNDEFS CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains']), - (1, executable+': failed CONTROL_FLOW')) - self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains']), - (0, '')) + pass_flags = ['-Wl,-pie', '-fstack-protector-all', '-fcf-protection=full', '-Wl,-fixup_chains'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_pie', '-Wl,-no_fixup_chains']), (1, executable+': failed FIXUP_CHAINS PIE')) # -fixup_chains is incompatible with -no_pie + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fcf-protection=none']), (1, executable + ': failed CONTROL_FLOW')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) else: - # arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-no_fixup_chains']), - (1, executable+': failed NOUNDEFS Canary FIXUP_CHAINS BRANCH_PROTECTION')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (1, executable+': failed NOUNDEFS Canary')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (1, executable+': failed NOUNDEFS')) - self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti']), - (0, '')) - + # arm64 darwin doesn't support non-PIE binaries or executable stacks + pass_flags = ['-fstack-protector-all', '-Wl,-fixup_chains', '-mbranch-protection=bti'] + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-mbranch-protection=none']), (1, executable + ': failed BRANCH_PROTECTION')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-no_fixup_chains']), (1, executable + ': failed FIXUP_CHAINS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-fno-stack-protector']), (1, executable + ': failed CANARY')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags + ['-Wl,-flat_namespace']), (1, executable + ': failed NOUNDEFS')) + self.assertEqual(call_security_check(cxx, source, executable, pass_flags), (0, '')) clean_files(source, executable) diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py index b00004586c..454dbc6bd2 100755 --- a/contrib/devtools/test-symbol-check.py +++ b/contrib/devtools/test-symbol-check.py @@ -11,17 +11,17 @@ import unittest from utils import determine_wellknown_cmd -def call_symbol_check(cc: list[str], source, executable, options): +def call_symbol_check(cxx: list[str], source, executable, options): # This should behave the same as AC_TRY_LINK, so arrange well-known flags # in the same order as autoconf would. # # See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for # reference. env_flags: list[str] = [] - for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']: + for var in ['CXXFLAGS', 'CPPFLAGS', 'LDFLAGS']: env_flags += filter(None, os.environ.get(var, '').split(' ')) - subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True) + subprocess.run([*cxx,source,'-o',executable] + env_flags + options, check=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) @@ -29,13 +29,13 @@ def call_symbol_check(cc: list[str], source, executable, options): class TestSymbolChecks(unittest.TestCase): def test_ELF(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1' - cc = determine_wellknown_cmd('CC', 'gcc') + cxx = determine_wellknown_cmd('CXX', 'g++') # -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' + source = 'test2.cpp' executable = 'test2' with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -48,31 +48,31 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-lutil']), (1, executable + ': libutil.so.1 is not in ALLOWED_LIBRARIES!\n' + executable + ': failed LIBRARY_DEPENDENCIES')) # finally, check a simple conforming binary - source = 'test3.c' + source = 'test3.cpp' executable = 'test3' with open(source, 'w', encoding="utf8") as f: f.write(''' - #include <stdio.h> + #include <cstdio> int main() { - printf("42"); + std::printf("42"); return 0; } ''') - self.assertEqual(call_symbol_check(cc, source, executable, []), + self.assertEqual(call_symbol_check(cxx, source, executable, []), (0, '')) def test_MACHO(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1' - cc = determine_wellknown_cmd('CC', 'clang') + cxx = determine_wellknown_cmd('CXX', 'clang++') with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -86,11 +86,11 @@ class TestSymbolChecks(unittest.TestCase): ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-lexpat', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-lexpat', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']), (1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' + f'{executable}: failed DYNAMIC_LIBRARIES MIN_OS SDK')) - source = 'test2.c' + source = 'test2.cpp' executable = 'test2' with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -103,10 +103,10 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-framework', 'CoreGraphics', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-framework', 'CoreGraphics', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']), (1, f'{executable}: failed MIN_OS SDK')) - source = 'test3.c' + source = 'test3.cpp' executable = 'test3' with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -116,13 +116,13 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']), (1, f'{executable}: failed SDK')) def test_PE(self): - source = 'test1.c' + source = 'test1.cpp' executable = 'test1.exe' - cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc') + cxx = determine_wellknown_cmd('CXX', 'x86_64-w64-mingw32-g++') with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -135,11 +135,11 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']), (1, 'pdh.dll is not in ALLOWED_LIBRARIES!\n' + executable + ': failed DYNAMIC_LIBRARIES')) - source = 'test2.c' + source = 'test2.cpp' executable = 'test2.exe' with open(source, 'w', encoding="utf8") as f: @@ -150,10 +150,10 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9']), (1, executable + ': failed SUBSYSTEM_VERSION')) - source = 'test3.c' + source = 'test3.cpp' executable = 'test3.exe' with open(source, 'w', encoding="utf8") as f: f.write(''' @@ -166,7 +166,7 @@ class TestSymbolChecks(unittest.TestCase): } ''') - self.assertEqual(call_symbol_check(cc, source, executable, ['-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']), + self.assertEqual(call_symbol_check(cxx, source, executable, ['-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']), (0, '')) diff --git a/contrib/devtools/test_utxo_snapshots.sh b/contrib/devtools/test_utxo_snapshots.sh index d7c019f4a6..ad948d4a14 100755 --- a/contrib/devtools/test_utxo_snapshots.sh +++ b/contrib/devtools/test_utxo_snapshots.sh @@ -138,7 +138,7 @@ echo echo "-- Now: add the following to CMainParams::m_assumeutxo_data" echo " in src/kernel/chainparams.cpp, and recompile:" echo -echo " {${RPC_BASE_HEIGHT}, AssumeutxoHash{uint256S(\"0x${RPC_AU}\")}, ${RPC_NCHAINTX}, uint256S(\"0x${RPC_BLOCKHASH}\")}," +echo " {.height = ${RPC_BASE_HEIGHT}, .hash_serialized = AssumeutxoHash{uint256{\"${RPC_AU}\"}}, .m_chain_tx_count = ${RPC_NCHAINTX}, .blockhash = consteval_ctor(uint256{\"${RPC_BLOCKHASH}\"})}," echo echo echo "-- IBDing more blocks to the server node (height=$FINAL_HEIGHT) so there is a diff between snapshot and tip..." diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md index 35ea83e585..10f5835bb8 100644 --- a/contrib/guix/INSTALL.md +++ b/contrib/guix/INSTALL.md @@ -671,6 +671,8 @@ More information: https://github.com/python/cpython/issues/81765 OpenSSL includes tests that will fail once some certificate has expired. The workarounds from the GnuTLS section immediately below can be used. +For openssl-1.1.1l use 2022-05-01 as the date. + ### GnuTLS: test-suite FAIL: status-request-revoked *The derivation is likely identified by: `/gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv`* @@ -705,11 +707,12 @@ authorized. This workaround was described [here](https://issues.guix.gnu.org/44559#5). Basically: -2. Turn off NTP -3. Set system time to 2020-10-01 -4. guix build --no-substitutes /gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv -5. Set system time back to accurate current time -6. Turn NTP back on + +1. Turn off NTP +2. Set system time to 2020-10-01 +3. guix build --no-substitutes /gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv +4. Set system time back to accurate current time +5. Turn NTP back on For example, diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 9bc8c0e75d..fa6933b332 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -71,11 +71,9 @@ unset OBJCPLUS_INCLUDE_PATH 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" case "$HOST" in - *darwin*) export LIBRARY_PATH="${NATIVE_GCC}/lib" ;; + *darwin*) export LIBRARY_PATH="${NATIVE_GCC}/lib" ;; # Required for qt/qmake *mingw*) export LIBRARY_PATH="${NATIVE_GCC}/lib" ;; *) NATIVE_GCC_STATIC="$(store_path gcc-toolchain static)" @@ -180,6 +178,14 @@ make -C depends --jobs="$JOBS" HOST="$HOST" \ x86_64_linux_NM=x86_64-linux-gnu-gcc-nm \ x86_64_linux_STRIP=x86_64-linux-gnu-strip +case "$HOST" in + *darwin*) + # Unset now that Qt is built + unset C_INCLUDE_PATH + unset CPLUS_INCLUDE_PATH + unset LIBRARY_PATH + ;; +esac ########################### # Source Tarball Building # diff --git a/contrib/guix/libexec/prelude.bash b/contrib/guix/libexec/prelude.bash index 80bfb2875f..9cc151c706 100644 --- a/contrib/guix/libexec/prelude.bash +++ b/contrib/guix/libexec/prelude.bash @@ -51,7 +51,7 @@ fi time-machine() { # shellcheck disable=SC2086 guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \ - --commit=f0bb724211872cd6158fce6162e0b8c73efed126 \ + --commit=7bf1d7aeaffba15c4f680f93ae88fbef25427252 \ --cores="$JOBS" \ --keep-failed \ --fallback \ diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index 44fbfa1c0b..1a47e91b49 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -25,6 +25,7 @@ (guix build-system gnu) (guix build-system python) (guix build-system trivial) + (guix download) (guix gexp) (guix git-download) ((guix licenses) #:prefix license:) @@ -91,7 +92,18 @@ chain for " target " development.")) (home-page (package-home-page xgcc)) (license (package-license xgcc))))) -(define base-gcc gcc-12) +(define base-gcc + (package + (inherit gcc-12) ;; 12.3.0 + (version "12.4.0") + (source (origin + (method url-fetch) + (uri (string-append "mirror://gnu/gcc/gcc-" + version "/gcc-" version ".tar.xz")) + (sha256 + (base32 + "0xcida8l2wykvvzvpcrcn649gj0ijn64gwxbplacpg6c0hk6akvh")))))) + (define base-linux-kernel-headers linux-libre-headers-6.1) (define* (make-bitcoin-cross-toolchain target @@ -116,10 +128,17 @@ desirable for building Bitcoin Core release binaries." (package-with-extra-patches binutils (search-our-patches "binutils-unaligned-default.patch"))) +(define (winpthreads-patches mingw-w64-x86_64-winpthreads) + (package-with-extra-patches mingw-w64-x86_64-winpthreads + (search-our-patches "winpthreads-remap-guix-store.patch"))) + (define (make-mingw-pthreads-cross-toolchain target) "Create a cross-compilation toolchain package for TARGET" (let* ((xbinutils (binutils-mingw-patches (cross-binutils target))) - (pthreads-xlibc mingw-w64-x86_64-winpthreads) + (machine (substring target 0 (string-index target #\-))) + (pthreads-xlibc (winpthreads-patches (make-mingw-w64 machine + #:xgcc (cross-gcc target #:xgcc (gcc-mingw-patches base-gcc)) + #:with-winpthreads? #t))) (pthreads-xgcc (cross-gcc target #:xgcc (gcc-mingw-patches mingw-w64-base-gcc) #:xbinutils xbinutils @@ -500,13 +519,13 @@ inspecting signatures in Mach-O binaries.") gzip xz ;; Build tools + gcc-toolchain-12 cmake-minimal gnu-make libtool autoconf-2.71 automake pkg-config - bison ;; Scripting python-minimal ;; (3.10) ;; Git @@ -515,22 +534,17 @@ inspecting signatures in Mach-O binaries.") python-lief) (let ((target (getenv "HOST"))) (cond ((string-suffix? "-mingw32" target) - (list ;; Native GCC 12 toolchain - gcc-toolchain-12 - zip + (list zip (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32") nsis-x86_64 nss-certs osslsigncode)) ((string-contains target "-linux-") - (list ;; Native GCC 12 toolchain - gcc-toolchain-12 + (list bison (list gcc-toolchain-12 "static") (make-bitcoin-cross-toolchain target))) ((string-contains target "darwin") - (list ;; Native GCC 11 toolchain - gcc-toolchain-11 - clang-toolchain-18 + (list clang-toolchain-18 lld-18 (make-lld-wrapper lld-18 #:lld-as-ld? #t) python-signapple diff --git a/contrib/guix/patches/gcc-remap-guix-store.patch b/contrib/guix/patches/gcc-remap-guix-store.patch index a47ef7a2df..a8b41d485b 100644 --- a/contrib/guix/patches/gcc-remap-guix-store.patch +++ b/contrib/guix/patches/gcc-remap-guix-store.patch @@ -1,14 +1,9 @@ -From aad25427e74f387412e8bc9a9d7bbc6c496c792f Mon Sep 17 00:00:00 2001 -From: Andrew Chow <achow101-github@achow101.com> -Date: Wed, 6 Jul 2022 16:49:41 -0400 -Subject: [PATCH] guix: remap guix store paths to /usr +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. ---- - libgcc/Makefile.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in -index 851e7657d07..476c2becd1c 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -854,7 +854,7 @@ endif diff --git a/contrib/guix/patches/winpthreads-remap-guix-store.patch b/contrib/guix/patches/winpthreads-remap-guix-store.patch new file mode 100644 index 0000000000..e1f1a6eba5 --- /dev/null +++ b/contrib/guix/patches/winpthreads-remap-guix-store.patch @@ -0,0 +1,17 @@ +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. + +--- a/mingw-w64-libraries/winpthreads/Makefile.in ++++ b/mingw-w64-libraries/winpthreads/Makefile.in +@@ -478,7 +478,7 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + SUBDIRS = . tests +-AM_CFLAGS = -Wall -DWIN32_LEAN_AND_MEAN $(am__append_1) ++AM_CFLAGS = -Wall -DWIN32_LEAN_AND_MEAN $(am__append_1) $(shell find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;) + ACLOCAL_AMFLAGS = -I m4 + lib_LTLIBRARIES = libwinpthread.la + include_HEADERS = include/pthread.h include/sched.h include/semaphore.h include/pthread_unistd.h include/pthread_time.h include/pthread_compat.h include/pthread_signal.h diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 24f6b29a26..74d9830705 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -76,6 +76,16 @@ def getFirstBlockFileId(block_dir_path): blkId = int(firstBlkFn[3:8]) return blkId +def read_xor_key(blocks_path): + NUM_XOR_BYTES = 8 # From InitBlocksdirXorKey::xor_key.size() + try: + xor_filename = os.path.join(blocks_path, "xor.dat") + with open(xor_filename, "rb") as xor_file: + return xor_file.read(NUM_XOR_BYTES) + # support also blockdirs created with pre-v28 versions, where no xor key exists yet + except FileNotFoundError: + return bytes([0] * NUM_XOR_BYTES) + # Block header and extent on disk BlockExtent = namedtuple('BlockExtent', ['fn', 'offset', 'inhdr', 'blkhdr', 'size']) @@ -95,6 +105,7 @@ class BlockDataCopier: self.outFname = None self.blkCountIn = 0 self.blkCountOut = 0 + self.xor_key = read_xor_key(self.settings['input']) self.lastDate = datetime.datetime(2000, 1, 1) self.highTS = 1408893517 - 315360000 @@ -113,6 +124,13 @@ class BlockDataCopier: self.outOfOrderData = {} self.outOfOrderSize = 0 # running total size for items in outOfOrderData + def read_xored(self, f, size): + offset = f.tell() + data = bytearray(f.read(size)) + for i in range(len(data)): + data[i] ^= self.xor_key[(i + offset) % len(self.xor_key)] + return bytes(data) + def writeBlock(self, inhdr, blk_hdr, rawblock): blockSizeOnDisk = len(inhdr) + len(blk_hdr) + len(rawblock) if not self.fileOutput and ((self.outsz + blockSizeOnDisk) > self.maxOutSz): @@ -165,7 +183,7 @@ class BlockDataCopier: '''Fetch block contents from disk given extents''' with open(self.inFileName(extent.fn), "rb") as f: f.seek(extent.offset) - return f.read(extent.size) + return self.read_xored(f, extent.size) def copyOneBlock(self): '''Find the next block to be written in the input, and copy it to the output.''' @@ -190,7 +208,7 @@ class BlockDataCopier: print("Premature end of block data") return - inhdr = self.inF.read(8) + inhdr = self.read_xored(self.inF, 8) if (not inhdr or (inhdr[0] == "\0")): self.inF.close() self.inF = None @@ -207,7 +225,7 @@ class BlockDataCopier: inLenLE = inhdr[4:] su = struct.unpack("<I", inLenLE) inLen = su[0] - 80 # length without header - blk_hdr = self.inF.read(80) + blk_hdr = self.read_xored(self.inF, 80) inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen) self.hash_str = calc_hash_str(blk_hdr) @@ -224,7 +242,7 @@ class BlockDataCopier: if self.blkCountOut == blkHeight: # If in-order block, just copy - rawblock = self.inF.read(inLen) + rawblock = self.read_xored(self.inF, inLen) self.writeBlock(inhdr, blk_hdr, rawblock) # See if we can catch up to prior out-of-order blocks @@ -237,7 +255,7 @@ class BlockDataCopier: # If there is space in the cache, read the data # Reading the data in file sequence instead of seeking and fetching it later is preferred, # but we don't want to fill up memory - self.outOfOrderData[blkHeight] = self.inF.read(inLen) + self.outOfOrderData[blkHeight] = self.read_xored(self.inF, inLen) self.outOfOrderSize += inLen else: # If no space in cache, seek forward self.inF.seek(inLen, os.SEEK_CUR) diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index f67e7b0f4c..72dd5d28cc 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -5,11 +5,12 @@ ''' Script to generate list of seed nodes for kernel/chainparams.cpp. -This script expects two text files in the directory that is passed as an +This script expects three text files in the directory that is passed as an argument: nodes_main.txt nodes_test.txt + nodes_testnet4.txt These files must consist of lines in the format @@ -171,6 +172,9 @@ def main(): g.write('\n') with open(os.path.join(indir,'nodes_test.txt'), 'r', encoding="utf8") as f: process_nodes(g, f, 'chainparams_seed_test') + g.write('\n') + with open(os.path.join(indir,'nodes_testnet4.txt'), 'r', encoding="utf8") as f: + process_nodes(g, f, 'chainparams_seed_testnet4') g.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n') if __name__ == '__main__': diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 564381d1e9..a50e36110d 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -50,17 +50,11 @@ darwin_STRIP=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-strip") # Disable adhoc codesigning (for now) when using LLVM tooling, to avoid # non-determinism issues with the Identifier field. -darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \ - -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \ - -u LIBRARY_PATH \ - $(clang_prog) --target=$(host) \ +darwin_CC=$(clang_prog) --target=$(host) \ -isysroot$(OSX_SDK) -nostdlibinc \ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks -darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \ - -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \ - -u LIBRARY_PATH \ - $(clangxx_prog) --target=$(host) \ +darwin_CXX=$(clangxx_prog) --target=$(host) \ -isysroot$(OSX_SDK) -nostdlibinc \ -iwithsysroot/usr/include/c++/v1 \ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index 2ec660109c..fb7d509938 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -3,19 +3,25 @@ $(package)_version=2.4.8 $(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/ $(package)_file_name=$(package)-$($(package)_version).tar.xz $(package)_sha256_hash=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df479dcaf25 +$(package)_build_subdir=build +$(package)_patches += cmake_minimum.patch # -D_DEFAULT_SOURCE defines __USE_MISC, which exposes additional # definitions in endian.h, which are required for a working # endianness check in configure when building with -flto. define $(package)_set_vars - $(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples - $(package)_config_opts += --disable-dependency-tracking --enable-option-checking - $(package)_config_opts += --without-xmlwf + $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DEXPAT_BUILD_TOOLS=OFF + $(package)_config_opts += -DEXPAT_BUILD_EXAMPLES=OFF -DEXPAT_BUILD_TESTS=OFF + $(package)_config_opts += -DBUILD_SHARED_LIBS=OFF $(package)_cppflags += -D_DEFAULT_SOURCE endef +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch +endef + define $(package)_config_cmds - $($(package)_autoconf) + $($(package)_cmake) -S .. -B . endef define $(package)_build_cmds @@ -27,5 +33,5 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds - rm -rf share lib/cmake lib/*.la + rm -rf share lib/cmake endef diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index c28259ed67..fef0beaa7b 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -3,14 +3,17 @@ $(package)_version=2.11.0 $(package)_download_path=https://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.xz $(package)_sha256_hash=8bee39bd3968c4804b70614a0a3ad597299ad0e824bc8aad5ce8aaf48067bde7 +$(package)_build_subdir=build define $(package)_set_vars - $(package)_config_opts=--without-zlib --without-png --without-harfbuzz --without-bzip2 --disable-static - $(package)_config_opts += --enable-option-checking --without-brotli + $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DBUILD_SHARED_LIBS=TRUE + $(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_ZLIB=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_PNG=TRUE + $(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE + $(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE endef define $(package)_config_cmds - $($(package)_autoconf) + $($(package)_cmake) -S .. -B . endef define $(package)_build_cmds @@ -21,6 +24,3 @@ define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install endef -define $(package)_postprocess_cmds - rm -rf share/man lib/*.la -endef diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index d764be5d0a..24e940eaa0 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -3,14 +3,17 @@ $(package)_version=2.1.12-stable $(package)_download_path=https://github.com/libevent/libevent/releases/download/release-$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb +$(package)_patches=cmake_fixups.patch +$(package)_patches+=fix_mingw_link.patch +$(package)_build_subdir=build # When building for Windows, we set _WIN32_WINNT to target the same Windows # version as we do in configure. Due to quirks in libevents build system, this # is also required to enable support for ipv6. See #19375. define $(package)_set_vars - $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples - $(package)_config_opts += --disable-dependency-tracking --enable-option-checking - $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts=-DEVENT__DISABLE_BENCHMARK=ON -DEVENT__DISABLE_OPENSSL=ON + $(package)_config_opts+=-DEVENT__DISABLE_SAMPLES=ON -DEVENT__DISABLE_REGRESS=ON + $(package)_config_opts+=-DEVENT__DISABLE_TESTS=ON -DEVENT__LIBRARY_TYPE=STATIC $(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601 ifeq ($(NO_HARDEN),) @@ -19,11 +22,12 @@ define $(package)_set_vars endef define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux + patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch && \ + patch -p1 < $($(package)_patch_dir)/fix_mingw_link.patch endef define $(package)_config_cmds - $($(package)_autoconf) + $($(package)_cmake) -S .. -B . endef define $(package)_build_cmds @@ -35,7 +39,7 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds - rm lib/*.la && \ + rm -rf bin && \ rm include/ev*.h && \ rm include/event2/*_compat.h endef diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 341031b5f8..f9e114b495 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,6 +1,6 @@ package=miniupnpc $(package)_version=2.2.7 -$(package)_download_path=http://miniupnp.free.fr/files/ +$(package)_download_path=https://miniupnp.tuxfamily.org/files/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=b0c3a27056840fd0ec9328a5a9bac3dc5e0ec6d2e8733349cf577b0aa1e70ac1 $(package)_patches=dont_leak_info.patch cmake_get_src_addr.patch fix_windows_snprintf.patch @@ -29,3 +29,8 @@ endef define $(package)_stage_cmds cmake --install . --prefix $($(package)_staging_prefix_dir) endef + +define $(package)_postprocess_cmds + rm -rf bin && \ + rm -rf share +endef diff --git a/depends/packages/native_libmultiprocess.mk b/depends/packages/native_libmultiprocess.mk index bcdb1f9e7c..2e30be434c 100644 --- a/depends/packages/native_libmultiprocess.mk +++ b/depends/packages/native_libmultiprocess.mk @@ -1,8 +1,8 @@ package=native_libmultiprocess -$(package)_version=8da797c5f1644df1bffd84d10c1ae9836dc70d60 +$(package)_version=6aca5f389bacf2942394b8738bbe15d6c9edfb9b $(package)_download_path=https://github.com/chaincodelabs/libmultiprocess/archive $(package)_file_name=$($(package)_version).tar.gz -$(package)_sha256_hash=030f4d393d2ac9deba98d2e1973e22fc439ffc009d5f8ae3225c90639f86beb0 +$(package)_sha256_hash=2efeed53542bc1d8af3291f2b6f0e5d430d86a5e04e415ce33c136f2c226a51d $(package)_dependencies=native_capnp define $(package)_config_cmds diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 4216646063..e3f614091d 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -28,3 +28,7 @@ endef define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install endef + +define $(package)_postprocess_cmds + rm -rf share +endef diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d35139dd2d..b133539495 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -23,6 +23,7 @@ $(package)_patches += memory_resource.patch $(package)_patches += clang_18_libpng.patch $(package)_patches += utc_from_string_no_optimize.patch $(package)_patches += windows_lto.patch +$(package)_patches += darwin_no_libm.patch $(package)_patches += zlib-timebits64.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) @@ -236,6 +237,7 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/utc_from_string_no_optimize.patch && \ patch -p1 -i $($(package)_patch_dir)/guix_cross_lib_path.patch && \ patch -p1 -i $($(package)_patch_dir)/windows_lto.patch && \ + patch -p1 -i $($(package)_patch_dir)/darwin_no_libm.patch && \ patch -p1 -i $($(package)_patch_dir)/zlib-timebits64.patch && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index bfa5e97c60..df018a1032 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -3,34 +3,48 @@ $(package)_version=4.3.5 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=6653ef5910f17954861fe72332e68b03ca6e4d9c7160eb3a8de5a5a913bfab43 -$(package)_patches=remove_libstd_link.patch +$(package)_build_subdir=build +$(package)_patches = remove_libstd_link.patch +$(package)_patches += macos_mktemp_check.patch +$(package)_patches += builtin_sha1.patch +$(package)_patches += fix_have_windows.patch +$(package)_patches += openbsd_kqueue_headers.patch +$(package)_patches += cmake_minimum.patch +$(package)_patches += cacheline_undefined.patch +$(package)_patches += no_librt.patch define $(package)_set_vars - $(package)_config_opts = --without-docs --disable-shared --disable-valgrind - $(package)_config_opts += --disable-perf --disable-curve-keygen --disable-curve --disable-libbsd - $(package)_config_opts += --without-libsodium --without-libgssapi_krb5 --without-pgm --without-norm --without-vmci - $(package)_config_opts += --disable-libunwind --disable-radix-tree --without-gcov --disable-dependency-tracking - $(package)_config_opts += --disable-Werror --disable-drafts --enable-option-checking + $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DWITH_DOCS=OFF -DWITH_LIBSODIUM=OFF + $(package)_config_opts += -DWITH_LIBBSD=OFF -DENABLE_CURVE=OFF -DENABLE_CPACK=OFF + $(package)_config_opts += -DBUILD_SHARED=OFF -DBUILD_TESTS=OFF -DZMQ_BUILD_TESTS=OFF + $(package)_config_opts += -DENABLE_DRAFTS=OFF -DZMQ_BUILD_TESTS=OFF + $(package)_cxxflags += -ffile-prefix-map=$($(package)_extract_dir)=/usr + $(package)_config_opts_mingw32 += -DZMQ_WIN32_WINNT=0x0601 -DZMQ_HAVE_IPC=OFF endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch + patch -p1 < $($(package)_patch_dir)/remove_libstd_link.patch && \ + patch -p1 < $($(package)_patch_dir)/macos_mktemp_check.patch && \ + patch -p1 < $($(package)_patch_dir)/builtin_sha1.patch && \ + patch -p1 < $($(package)_patch_dir)/cacheline_undefined.patch && \ + patch -p1 < $($(package)_patch_dir)/fix_have_windows.patch && \ + patch -p1 < $($(package)_patch_dir)/openbsd_kqueue_headers.patch && \ + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch && \ + patch -p1 < $($(package)_patch_dir)/no_librt.patch endef define $(package)_config_cmds - ./autogen.sh && \ - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config && \ - $($(package)_autoconf) + $($(package)_cmake) -S .. -B . endef define $(package)_build_cmds - $(MAKE) src/libzmq.la + $(MAKE) endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-pkgconfigDATA + $(MAKE) DESTDIR=$($(package)_staging_dir) install endef define $(package)_postprocess_cmds - rm -rf bin share lib/*.la + rm -rf share endef diff --git a/depends/patches/expat/cmake_minimum.patch b/depends/patches/expat/cmake_minimum.patch new file mode 100644 index 0000000000..a849a82a33 --- /dev/null +++ b/depends/patches/expat/cmake_minimum.patch @@ -0,0 +1,13 @@ +build: set minimum required CMake to 3.16 + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -33,7 +33,7 @@ + # Unlike most of Expat, + # this file is copyrighted under the BSD-license for buildsystem files of KDE. + +-cmake_minimum_required(VERSION 3.1.3) ++cmake_minimum_required(VERSION 3.16) + + # This allows controlling documented build time switches + # when Expat is pulled in using the add_subdirectory function, e.g. diff --git a/depends/patches/libevent/cmake_fixups.patch b/depends/patches/libevent/cmake_fixups.patch new file mode 100644 index 0000000000..d80c1a9489 --- /dev/null +++ b/depends/patches/libevent/cmake_fixups.patch @@ -0,0 +1,35 @@ +cmake: set minimum version to 3.5 + +Fix generated pkg-config files, see +https://github.com/libevent/libevent/pull/1165. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -19,7 +19,7 @@ + # start libevent.sln + # + +-cmake_minimum_required(VERSION 3.1 FATAL_ERROR) ++cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + + if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +diff --git a/cmake/AddEventLibrary.cmake b/cmake/AddEventLibrary.cmake +index 04f5837e..d8ea42c4 100644 +--- a/cmake/AddEventLibrary.cmake ++++ b/cmake/AddEventLibrary.cmake +@@ -20,12 +20,12 @@ macro(generate_pkgconfig LIB_NAME) + + set(LIBS "") + foreach (LIB ${LIB_PLATFORM}) +- set(LIBS "${LIBS} -L${LIB}") ++ set(LIBS "${LIBS} -l${LIB}") + endforeach() + + set(OPENSSL_LIBS "") + foreach(LIB ${OPENSSL_LIBRARIES}) +- set(OPENSSL_LIBS "${OPENSSL_LIBS} -L${LIB}") ++ set(OPENSSL_LIBS "${OPENSSL_LIBS} -l${LIB}") + endforeach() + + configure_file("lib${LIB_NAME}.pc.in" "lib${LIB_NAME}.pc" @ONLY) diff --git a/depends/patches/libevent/fix_mingw_link.patch b/depends/patches/libevent/fix_mingw_link.patch new file mode 100644 index 0000000000..41cbd463c9 --- /dev/null +++ b/depends/patches/libevent/fix_mingw_link.patch @@ -0,0 +1,25 @@ +commit d108099913c5fdbe518f3f4d711f248f8522bd10 +Author: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> +Date: Mon Apr 22 06:39:35 2024 +0100 + + build: Add `Iphlpapi` to `Libs.private` in `*.pc` files on Windows + + It has been required since https://github.com/libevent/libevent/pull/923 + at least for the `if_nametoindex` call. + + See https://github.com/libevent/libevent/pull/1622. + + +diff --git a/configure.ac b/configure.ac +index d00e063a..cd1fce37 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -906,7 +906,7 @@ if(WIN32) + list(APPEND HDR_PRIVATE WIN32-Code/getopt.h) + + set(EVENT__DNS_USE_FTIME_FOR_ID 1) +- set(LIB_PLATFORM ws2_32 shell32 advapi32) ++ set(LIB_PLATFORM ws2_32 shell32 advapi32 iphlpapi) + add_definitions( + -D_CRT_SECURE_NO_WARNINGS + -D_CRT_NONSTDC_NO_DEPRECATE) diff --git a/depends/patches/qt/darwin_no_libm.patch b/depends/patches/qt/darwin_no_libm.patch new file mode 100644 index 0000000000..38a94beeb7 --- /dev/null +++ b/depends/patches/qt/darwin_no_libm.patch @@ -0,0 +1,17 @@ +build: remove explicit -lm link from qttools + +This causes issues with at least the macOS cross build, and shouldn't +actually be required anywhere else. GCC with libstdc++ will already get libm. + +--- a/qtbase/src/corelib/tools/tools.pri ++++ b/qtbase/src/corelib/tools/tools.pri +@@ -111,9 +111,6 @@ qtConfig(easingcurve) { + tools/qtimeline.cpp + } + +-# Note: libm should be present by default becaue this is C++ +-unix:!macx-icc:!vxworks:!haiku:!integrity:!wasm: LIBS_PRIVATE += -lm +- + TR_EXCLUDE += ../3rdparty/* + + # MIPS DSP diff --git a/depends/patches/qt/dont_hardcode_pwd.patch b/depends/patches/qt/dont_hardcode_pwd.patch index a74e9cb098..f6955b2f20 100644 --- a/depends/patches/qt/dont_hardcode_pwd.patch +++ b/depends/patches/qt/dont_hardcode_pwd.patch @@ -1,13 +1,13 @@ -commit 0e953866fc4672486e29e1ba6d83b4207e7b2f0b -Author: fanquake <fanquake@gmail.com> -Date: Tue Aug 18 15:09:06 2020 +0800 +Do not assume FHS in scripts - Don't hardcode pwd path +On systems that do not follow the Filesystem Hierarchy Standard, such as +guix, the hardcoded `/bin/pwd` will fail to be found so that the script +will fail. - Let a man use his builtins if he wants to! Also, removes the unnecessary - assumption that pwd lives under /bin/pwd. +Use `pwd`, instead, so that the command can be found through the normal +path search mechanism. - See #15581. +See https://github.com/qt/qtbase/commit/3388de698bfb9bbc456c08f03e83bf3e749df35c. diff --git a/qtbase/configure b/qtbase/configure index 08b49a8d..faea5b55 100755 diff --git a/depends/patches/zeromq/builtin_sha1.patch b/depends/patches/zeromq/builtin_sha1.patch new file mode 100644 index 0000000000..5481c9dbdd --- /dev/null +++ b/depends/patches/zeromq/builtin_sha1.patch @@ -0,0 +1,17 @@ +Don't use builtin sha1 if not using ws + +The builtin SHA1 (ZMQ_USE_BUILTIN_SHA1) is only used in the websocket +engine (ws_engine.cpp). +Upstreamed in https://github.com/zeromq/libzmq/pull/4670. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -234,7 +234,7 @@ if(NOT ZMQ_USE_GNUTLS) + endif() + endif() + endif() +- if(NOT ZMQ_USE_NSS) ++ if(ENABLE_WS AND NOT ZMQ_USE_NSS) + list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.c + ${CMAKE_CURRENT_SOURCE_DIR}/external/sha1/sha1.h) + message(STATUS "Using builtin sha1") diff --git a/depends/patches/zeromq/cacheline_undefined.patch b/depends/patches/zeromq/cacheline_undefined.patch new file mode 100644 index 0000000000..02bd2a5fe5 --- /dev/null +++ b/depends/patches/zeromq/cacheline_undefined.patch @@ -0,0 +1,15 @@ +Use proper STREQUAL instead of EQUAL to compare strings.txt + +See: https://github.com/zeromq/libzmq/pull/4711. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -476,7 +476,7 @@ execute_process( + if(CACHELINE_SIZE STREQUAL "" + OR CACHELINE_SIZE EQUAL 0 + OR CACHELINE_SIZE EQUAL -1 +- OR CACHELINE_SIZE EQUAL "undefined") ++ OR CACHELINE_SIZE STREQUAL "undefined") + set(ZMQ_CACHELINE_SIZE 64) + else() + set(ZMQ_CACHELINE_SIZE ${CACHELINE_SIZE}) diff --git a/depends/patches/zeromq/cmake_minimum.patch b/depends/patches/zeromq/cmake_minimum.patch new file mode 100644 index 0000000000..d6b6b5fae7 --- /dev/null +++ b/depends/patches/zeromq/cmake_minimum.patch @@ -0,0 +1,18 @@ +Set a more sane cmake_minimum_required. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,12 +1,7 @@ + # CMake build script for ZeroMQ ++cmake_minimum_required(VERSION 3.16) + project(ZeroMQ) + +-if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) +- cmake_minimum_required(VERSION 3.0.2) +-else() +- cmake_minimum_required(VERSION 2.8.12) +-endif() +- + include(CheckIncludeFiles) + include(CheckCCompilerFlag) + include(CheckCXXCompilerFlag) diff --git a/depends/patches/zeromq/fix_have_windows.patch b/depends/patches/zeromq/fix_have_windows.patch new file mode 100644 index 0000000000..e77ef31adf --- /dev/null +++ b/depends/patches/zeromq/fix_have_windows.patch @@ -0,0 +1,54 @@ +This fixes several instances where _MSC_VER was +used to determine whether to use afunix.h or not. + +See https://github.com/zeromq/libzmq/pull/4678. +--- a/src/ipc_address.hpp ++++ b/src/ipc_address.hpp +@@ -7,7 +7,7 @@ + + #include <string> + +-#if defined _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #include <afunix.h> + #else + #include <sys/socket.h> +diff --git a/src/ipc_connecter.cpp b/src/ipc_connecter.cpp +index 3f988745..ed2a0645 100644 +--- a/src/ipc_connecter.cpp ++++ b/src/ipc_connecter.cpp +@@ -16,7 +16,7 @@ + #include "ipc_address.hpp" + #include "session_base.hpp" + +-#ifdef _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #include <afunix.h> + #else + #include <unistd.h> +diff --git a/src/ipc_listener.cpp b/src/ipc_listener.cpp +index 50126040..5428579b 100644 +--- a/src/ipc_listener.cpp ++++ b/src/ipc_listener.cpp +@@ -17,7 +17,7 @@ + #include "socket_base.hpp" + #include "address.hpp" + +-#ifdef _MSC_VER ++#ifdef ZMQ_HAVE_WINDOWS + #ifdef ZMQ_IOTHREAD_POLLER_USE_SELECT + #error On Windows, IPC does not work with POLLER=select, use POLLER=epoll instead, or disable IPC transport + #endif +diff --git a/tests/testutil.cpp b/tests/testutil.cpp +index bdc80283..6f21e8f6 100644 +--- a/tests/testutil.cpp ++++ b/tests/testutil.cpp +@@ -7,7 +7,7 @@ + + #if defined _WIN32 + #include "../src/windows.hpp" +-#if defined _MSC_VER ++#if defined ZMQ_HAVE_WINDOWS + #if defined ZMQ_HAVE_IPC + #include <direct.h> + #include <afunix.h> diff --git a/depends/patches/zeromq/macos_mktemp_check.patch b/depends/patches/zeromq/macos_mktemp_check.patch new file mode 100644 index 0000000000..c703abcd71 --- /dev/null +++ b/depends/patches/zeromq/macos_mktemp_check.patch @@ -0,0 +1,16 @@ +build: fix mkdtemp check on macOS + +On macOS, mkdtemp is in unistd.h. Fix the CMake check so that is works. +Upstreamed in https://github.com/zeromq/libzmq/pull/4668. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -599,7 +599,7 @@ if(NOT MSVC) + + check_cxx_symbol_exists(fork unistd.h HAVE_FORK) + check_cxx_symbol_exists(gethrtime sys/time.h HAVE_GETHRTIME) +- check_cxx_symbol_exists(mkdtemp stdlib.h HAVE_MKDTEMP) ++ check_cxx_symbol_exists(mkdtemp "stdlib.h;unistd.h" HAVE_MKDTEMP) + check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4) + check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN) + else() diff --git a/depends/patches/zeromq/no_librt.patch b/depends/patches/zeromq/no_librt.patch new file mode 100644 index 0000000000..b63854c95b --- /dev/null +++ b/depends/patches/zeromq/no_librt.patch @@ -0,0 +1,54 @@ +We don't use librt, so don't try and link against it. + +Related to: https://github.com/zeromq/libzmq/pull/4702. + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 03462271..87ceab3c 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -564,13 +564,6 @@ else() + check_cxx_symbol_exists(SO_BUSY_POLL sys/socket.h ZMQ_HAVE_BUSY_POLL) + endif() + +-if(NOT MINGW) +- find_library(RT_LIBRARY rt) +- if(RT_LIBRARY) +- set(pkg_config_libs_private "${pkg_config_libs_private} -lrt") +- endif() +-endif() +- + find_package(Threads) + + if(WIN32 AND NOT CYGWIN) +@@ -588,9 +581,7 @@ if(WIN32 AND NOT CYGWIN) + endif() + + if(NOT MSVC) +- set(CMAKE_REQUIRED_LIBRARIES rt) + check_cxx_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) +- set(CMAKE_REQUIRED_LIBRARIES) + + check_cxx_symbol_exists(fork unistd.h HAVE_FORK) + check_cxx_symbol_exists(gethrtime sys/time.h HAVE_GETHRTIME) +@@ -1503,10 +1494,6 @@ if(BUILD_SHARED) + target_link_libraries(libzmq iphlpapi) + endif() + +- if(RT_LIBRARY) +- target_link_libraries(libzmq -lrt) +- endif() +- + if(norm_FOUND) + target_link_libraries(libzmq norm::norm) + endif() +@@ -1553,10 +1540,6 @@ if(BUILD_STATIC) + target_link_libraries(libzmq-static iphlpapi) + endif() + +- if(RT_LIBRARY) +- target_link_libraries(libzmq-static -lrt) +- endif() +- + if(CMAKE_SYSTEM_NAME MATCHES "QNX") + add_definitions(-DUNITY_EXCLUDE_MATH_H) + endif() diff --git a/depends/patches/zeromq/openbsd_kqueue_headers.patch b/depends/patches/zeromq/openbsd_kqueue_headers.patch new file mode 100644 index 0000000000..7000e209fe --- /dev/null +++ b/depends/patches/zeromq/openbsd_kqueue_headers.patch @@ -0,0 +1,24 @@ +commit ff231d267370493814f933d151441866bf1e200b +Author: Min RK <benjaminrk@gmail.com> +Date: Fri Feb 23 13:21:08 2024 +0100 + + Problem: cmake search for kqueue missing headers + + Solution: include sys/types.h and sys/time.h as documented by kqueue + and used in autotools + + fixes kqueue detection on openbsd + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f956f3fd..814d5d46 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -380,7 +380,7 @@ endif(WIN32) + + if(NOT MSVC) + if(POLLER STREQUAL "") +- check_cxx_symbol_exists(kqueue sys/event.h HAVE_KQUEUE) ++ check_cxx_symbol_exists(kqueue "sys/types.h;sys/event.h;sys/time.h" HAVE_KQUEUE) + if(HAVE_KQUEUE) + set(POLLER "kqueue") + endif() diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 2d7d0e3769..6664bc2a3a 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -4,7 +4,7 @@ Unauthenticated REST Interface The REST API can be enabled with the `-rest` option. The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet, port 18332 for testnet, -port 38332 for signet, and port 18443 for regtest. +port 48332 for testnet4, port 38332 for signet, and port 18443 for regtest. REST Interface consistency guarantees ------------------------------------- diff --git a/doc/bips.md b/doc/bips.md index 19a8091f55..51ffe00a76 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -30,10 +30,11 @@ BIPs that are implemented by Bitcoin Core: * [`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 94`](https://github.com/bitcoin/bips/blob/master/bip-0094.mediawiki): Testnet 4 (`-testnet4`) supported as of **v28.0** ([PR #29775](https://github.com/bitcoin/bitcoin/pull/29775)). * [`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)). * [`BIP 113`](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki): Median time past lock-time calculations have been implemented since **v0.12.1** ([PR #6566](https://github.com/bitcoin/bitcoin/pull/6566)), and has been *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)). -* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling partially implemented. See doc/policy/mempool-replacements.md. +* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee partially implemented: signaling is enforced if configured. For other replacement rules, see doc/policy/mempool-replacements.md. * [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)). * [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)). * [`BIP 141`](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki): Segregated Witness (Consensus Layer) as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)), defined for mainnet as of **v0.13.1** ([PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)), and *buried* since **v0.19.0** ([PR #16060](https://github.com/bitcoin/bitcoin/pull/16060)). diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 264d5f2d08..0fba281dc1 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -66,6 +66,22 @@ Bitcoin Core includes a GUI built with the cross-platform Qt Framework. To compi pkg_add qtbase qttools ``` +###### libqrencode + +The GUI can encode addresses in a QR Code. To build in QR support for the GUI, install `libqrencode`. Skip if not using the GUI or don't want QR code functionality. +```bash +pkg_add libqrencode +``` +--- + +#### Notifications +###### ZeroMQ + +Bitcoin Core can provide notifications via ZeroMQ. If the package is installed, support will be compiled in. +```bash +pkg_add zeromq +``` + ## Building Bitcoin Core **Important**: Use `gmake` (the non-GNU `make` will exit with an error). diff --git a/doc/build-windows.md b/doc/build-windows.md index 841693c77b..1217f10c1b 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -13,6 +13,9 @@ Other options which may work, but which have not been extensively tested are (pl * On Windows, using a POSIX compatibility layer application such as [cygwin](https://www.cygwin.com/) or [msys2](https://www.msys2.org/). +The instructions below work on Ubuntu and Debian. Make sure the distribution's `g++-mingw-w64-x86-64-posix` +package meets the minimum required `g++` version specified in [dependencies.md](dependencies.md). + Installing Windows Subsystem for Linux --------------------------------------- @@ -29,7 +32,7 @@ First, install the general dependencies: sudo apt update sudo apt upgrade - sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git + sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils cmake curl git A host toolchain (`build-essential`) is necessary because some dependency packages need to build host utilities that are used in the build process. @@ -66,7 +69,6 @@ is to temporarily disable WSL support for Win32 applications. Build using: - PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var sudo bash -c "echo 0 > /proc/sys/fs/binfmt_misc/status" # Disable WSL support for Win32 applications. cd depends make HOST=x86_64-w64-mingw32 diff --git a/doc/dependencies.md b/doc/dependencies.md index 63c505c9cb..3bc931e8f6 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -8,7 +8,7 @@ You can find installation instructions in the `build-*.md` file for your platfor | --- | --- | | [Autoconf](https://www.gnu.org/software/autoconf/) | [2.69](https://github.com/bitcoin/bitcoin/pull/17769) | | [Automake](https://www.gnu.org/software/automake/) | [1.13](https://github.com/bitcoin/bitcoin/pull/18290) | -| [Clang](https://clang.llvm.org) | [15.0](https://github.com/bitcoin/bitcoin/pull/29165) | +| [Clang](https://clang.llvm.org) | [16.0](https://github.com/bitcoin/bitcoin/pull/30263) | | [GCC](https://gcc.gnu.org) | [11.1](https://github.com/bitcoin/bitcoin/pull/29091) | | [Python](https://www.python.org) (scripts, tests) | [3.9](https://github.com/bitcoin/bitcoin/pull/28211) | | [systemtap](https://sourceware.org/systemtap/) ([tracing](tracing.md))| N/A | diff --git a/doc/descriptors.md b/doc/descriptors.md index 3b94ec03e4..5e8e4a24b0 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -63,6 +63,7 @@ Output descriptors currently support: - `wsh(sortedmulti(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` describes a set of *1-of-2* P2WSH multisig outputs where one multisig key is the *1/0/`i`* child of the first specified xpub and the other multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). The order of public keys in the resulting witnessScripts is determined by the lexicographic order of the public keys at that index. - `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,{pk(fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),pk(e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)})` describes a P2TR output with the `c6...` x-only pubkey as internal key, and two script paths. - `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,sortedmulti_a(2,2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc))` describes a P2TR output with the `c6...` x-only pubkey as internal key, and a single `multi_a` script that needs 2 signatures with 2 specified x-only keys, which will be sorted lexicographically. +- `wsh(sortedmulti(2,[6f53d49c/44h/1h/0h]tpubDDjsCRDQ9YzyaAq9rspCfq8RZFrWoBpYnLxK6sS2hS2yukqSczgcYiur8Scx4Hd5AZatxTuzMtJQJhchufv1FRFanLqUP7JHwusSSpfcEp2/0/*,[e6807791/44h/1h/0h]tpubDDAfvogaaAxaFJ6c15ht7Tq6ZmiqFYfrSmZsHu7tHXBgnjMZSHAeHSwhvjARNA6Qybon4ksPksjRbPDVp7yXA1KjTjSd5x18KHqbppnXP1s/0/*,[367c9cfa/44h/1h/0h]tpubDDtPnSgWYk8dDnaDwnof4ehcnjuL5VoUt1eW2MoAed1grPHuXPDnkX1fWMvXfcz3NqFxPbhqNZ3QBdYjLz2hABeM9Z2oqMR1Gt2HHYDoCgh/0/*))#av0kxgw0` describes a *2-of-3* multisig. For brevity, the internal "change" descriptor accompanying the above external "receiving" descriptor is not included here, but it typically differs only in the xpub derivation steps, ending in `/1/*` for change addresses. ## Reference @@ -167,9 +168,9 @@ The basic steps are: the participant's signer wallet. Avoid reusing this wallet for any purpose other than signing transactions from the corresponding multisig we are about to create. Hint: extract the wallet's xpubs using `listdescriptors` and pick the one from the `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses) - 2. Create a watch-only descriptor wallet (blank, private keys disabled). Now the multisig is created by importing the two descriptors: + 2. Create a watch-only descriptor wallet (blank, private keys disabled). Now the multisig is created by importing the external and internal descriptors: `wsh(sortedmulti(<M>,XPUB1/0/*,XPUB2/0/*,…,XPUBN/0/*))` and `wsh(sortedmulti(<M>,XPUB1/1/*,XPUB2/1/*,…,XPUBN/1/*))` - (one descriptor w/ `0` for receiving addresses and another w/ `1` for change). Every participant does this + (one descriptor w/ `0` for receiving addresses and another w/ `1` for change). Every participant does this. All key origin information (master key fingerprint and all derivation steps) should be included with xpubs for proper support of hardware devices / external signers 3. A receiving address is generated for the multisig. As a check to ensure step 2 was done correctly, every participant should verify they get the same addresses 4. Funds are sent to the resulting address diff --git a/doc/design/libraries.md b/doc/design/libraries.md index aa8034ab37..caf414ac47 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -97,7 +97,7 @@ class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold - *libbitcoin_consensus* should only depend on *libbitcoin_crypto*, and all other libraries besides *libbitcoin_crypto* should be allowed to depend on it. -- *libbitcoin_util* should be a standalone dependency that any library can depend on, and it should not depend on other libraries except *libbitcoin_crypto*. It provides basic utilities that fill in gaps in the C++ standard library and provide lightweight abstractions over platform-specific features. Since the util library is distributed with the kernel and is usable by kernel applications, it shouldn't contain functions that external code shouldn't call, like higher level code targetted at the node or wallet. (*libbitcoin_common* is a better place for higher level code, or code that is meant to be used by internal applications only.) +- *libbitcoin_util* should be a standalone dependency that any library can depend on, and it should not depend on other libraries except *libbitcoin_crypto*. It provides basic utilities that fill in gaps in the C++ standard library and provide lightweight abstractions over platform-specific features. Since the util library is distributed with the kernel and is usable by kernel applications, it shouldn't contain functions that external code shouldn't call, like higher level code targeted at the node or wallet. (*libbitcoin_common* is a better place for higher level code, or code that is meant to be used by internal applications only.) - *libbitcoin_common* is a home for miscellaneous shared code used by different Bitcoin Core applications. It should not depend on anything other than *libbitcoin_util*, *libbitcoin_consensus*, and *libbitcoin_crypto*. @@ -109,5 +109,4 @@ class bitcoin-qt,bitcoind,bitcoin-cli,bitcoin-wallet bold ## Work in progress -- Validation code is moving from *libbitcoin_node* to *libbitcoin_kernel* as part of [The libbitcoinkernel Project #24303](https://github.com/bitcoin/bitcoin/issues/24303) -- Source code organization is discussed in general in [Library source code organization #15732](https://github.com/bitcoin/bitcoin/issues/15732) +- Validation code is moving from *libbitcoin_node* to *libbitcoin_kernel* as part of [The libbitcoinkernel Project #27587](https://github.com/bitcoin/bitcoin/issues/27587) diff --git a/doc/developer-notes.md b/doc/developer-notes.md index d9d5b392c5..0445921026 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -492,7 +492,7 @@ make cov # unit and functional tests. ``` -Additional LCOV options can be specified using `LCOV_OPTS`, but may be dependant +Additional LCOV options can be specified using `LCOV_OPTS`, but may be dependent on the version of LCOV. For example, when using LCOV `2.x`, branch coverage can be enabled by setting `LCOV_OPTS="--rc branch_coverage=1"`, when configuring. diff --git a/doc/files.md b/doc/files.md index 03e52f02c9..b738d6055a 100644 --- a/doc/files.md +++ b/doc/files.md @@ -34,12 +34,13 @@ Windows | `%LOCALAPPDATA%\Bitcoin\` <sup>[\[1\]](#note1)</sup> 3. All content of the data directory, except for `bitcoin.conf` file, is chain-specific. This means the actual data directory paths for non-mainnet cases differ: -Chain option | Data directory path --------------------------------|------------------------------ -`-chain=main` (default) | *path_to_datadir*`/` -`-chain=test` or `-testnet` | *path_to_datadir*`/testnet3/` -`-chain=signet` or `-signet` | *path_to_datadir*`/signet/` -`-chain=regtest` or `-regtest` | *path_to_datadir*`/regtest/` +Chain option | Data directory path +---------------------------------|------------------------------ +`-chain=main` (default) | *path_to_datadir*`/` +`-chain=test` or `-testnet` | *path_to_datadir*`/testnet3/` +`-chain=testnet4` or `-testnet4` | *path_to_datadir*`/testnet4/` +`-chain=signet` or `-signet` | *path_to_datadir*`/signet/` +`-chain=regtest` or `-regtest` | *path_to_datadir*`/regtest/` ## Data directory layout @@ -47,8 +48,9 @@ Subdirectory | File(s) | Description -------------------|-----------------------|------------ `blocks/` | | Blocks directory; can be specified by `-blocksdir` option (except for `blocks/index/`) `blocks/index/` | LevelDB database | Block index; `-blocksdir` option does not affect this path -`blocks/` | `blkNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Actual Bitcoin blocks (in network format, dumped in raw on disk, 128 MiB per file) +`blocks/` | `blkNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Actual Bitcoin blocks (dumped in network format, 128 MiB per file) `blocks/` | `revNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Block undo data (custom format) +`blocks/` | `xor.dat` | Rolling XOR pattern for block and undo data files `chainstate/` | LevelDB database | Blockchain state (a compact representation of all currently unspent transaction outputs (UTXOs) and metadata about the transactions they are from) `indexes/txindex/` | LevelDB database | Transaction index; *optional*, used if `-txindex=1` `indexes/blockfilter/basic/db/` | LevelDB database | Blockfilter index LevelDB database for the basic filtertype; *optional*, used if `-blockfilterindex=basic` diff --git a/doc/multisig-tutorial.md b/doc/multisig-tutorial.md index 1d2b3244bc..f47dd08ad1 100644 --- a/doc/multisig-tutorial.md +++ b/doc/multisig-tutorial.md @@ -16,8 +16,6 @@ This tutorial also uses the default WPKH derivation path to get the xpubs and do At the time of writing, there is no way to extract a specific path from wallets in Bitcoin Core. For this, an external signer/xpub can be used. -[PR #22341](https://github.com/bitcoin/bitcoin/pull/22341), which is still under development, introduces a new wallet RPC `getxpub`. It takes a BIP32 path as an argument and returns the xpub, along with the master key fingerprint. - ## 1.1 Basic Multisig Workflow ### 1.1 Create the Descriptor Wallets diff --git a/doc/policy/mempool-replacements.md b/doc/policy/mempool-replacements.md index d5642eaccc..f044a0f8ad 100644 --- a/doc/policy/mempool-replacements.md +++ b/doc/policy/mempool-replacements.md @@ -10,14 +10,12 @@ A transaction ("replacement transaction") may replace its directly conflicting t their in-mempool descendants (together, "original transactions") if, in addition to passing all other consensus and policy rules, each of the following conditions are met: -1. The directly conflicting transactions all signal replaceability explicitly. A transaction is +1. If `-mempoolfullrbf=0` (the value is 1 by default), the directly conflicting transactions all signal replaceability explicitly. A transaction is signaling BIP125 replaceability if any of its inputs have an nSequence number less than (0xffffffff - 1). A transaction also signals replaceability if its version field is set to 3. *Rationale*: See [BIP125 explanation](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#motivation). - Use the (`-mempoolfullrbf`) configuration option to allow transaction replacement without enforcement of the - opt-in signaling rule. 2. The replacement transaction only include an unconfirmed input if that input was included in one of the directly conflicting transactions. An unconfirmed input spends an output from a @@ -80,3 +78,5 @@ This set of rules is similar but distinct from BIP125. * Full replace-by-fee enabled as a configurable mempool policy as of **v24.0** ([PR #25353](https://github.com/bitcoin/bitcoin/pull/25353)). + +* Full replace-by-fee is the default policy as of **v28.0** ([PR #30493](https://github.com/bitcoin/bitcoin/pull/30493)). diff --git a/doc/policy/packages.md b/doc/policy/packages.md index a220bdd17f..b432008d7b 100644 --- a/doc/policy/packages.md +++ b/doc/policy/packages.md @@ -38,11 +38,11 @@ The following rules are enforced for all packages: * Only limited package replacements are currently considered. (#28984) - - All direct conflicts must signal replacement (or have `-mempoolfullrbf=1` set). + - If `-mempoolfullrbf=0` (the value is 1 by default), all direct conflicts must signal replacement. - Packages are 1-parent-1-child, with no in-mempool ancestors of the package. - - All conflicting clusters(connected components of mempool transactions) must be clusters of up to size 2. + - All conflicting clusters (connected components of mempool transactions) must be clusters of up to size 2. - No more than MAX_REPLACEMENT_CANDIDATES transactions can be replaced, analogous to regular [replacement rule](./mempool-replacements.md) 5). @@ -56,7 +56,7 @@ The following rules are enforced for all packages: - *Rationale*: Basic support for package RBF can be used by wallets by making chains of no longer than two, then directly conflicting - those chains when needed. Combined with V3 transactions this can + those chains when needed. Combined with TRUC transactions this can result in more robust fee bumping. More general package RBF may be enabled in the future. diff --git a/doc/productivity.md b/doc/productivity.md index e9b7bc270c..323d86f7b8 100644 --- a/doc/productivity.md +++ b/doc/productivity.md @@ -33,7 +33,7 @@ The easiest way to faster compile times is to cache compiles. `ccache` is a way Install `ccache` through your distribution's package manager, and run `./configure` with your normal flags to pick it up. -To use ccache for all your C/C++ projects, follow the symlinks method [here](https://ccache.samba.org/manual/latest.html#_run_modes) to set it up. +To use ccache for all your C/C++ projects, follow the symlinks method [here](https://ccache.dev/manual/latest.html#_run_modes) to set it up. To get the most out of ccache, put something like this in `~/.ccache/ccache.conf`: diff --git a/doc/release-notes-22729.md b/doc/release-notes-22729.md new file mode 100644 index 0000000000..7b836c2701 --- /dev/null +++ b/doc/release-notes-22729.md @@ -0,0 +1,21 @@ +Notable changes +=============== + +P2P and network changes +----------------------- + +- Previously if Bitcoin Core was listening for P2P connections, either using + default settings or via `bind=addr:port` it would always also bind to + `127.0.0.1:8334` to listen for Tor connections. It was not possible to switch + this off, even if the node didn't use Tor. This has been changed and now + `bind=addr:port` results in binding on `addr:port` only. The default behavior + of binding to `0.0.0.0:8333` and `127.0.0.1:8334` has not been changed. + + If you are using a `bind=...` configuration without `bind=...=onion` and rely + on the previous implied behavior to accept incoming Tor connections at + `127.0.0.1:8334`, you need to now make this explicit by using + `bind=... bind=127.0.0.1:8334=onion`. (#22729) + +- Bitcoin Core will now fail to start up if any of its P2P binds fail, rather + than the previous behaviour where it would only abort startup if all P2P + binds had failed. (#22729) diff --git a/doc/release-notes-28052.md b/doc/release-notes-28052.md new file mode 100644 index 0000000000..386f0cee5f --- /dev/null +++ b/doc/release-notes-28052.md @@ -0,0 +1,6 @@ +Blockstorage +============ + +Block files are now XOR'd by default with a key stored in the blocksdir. +Previous releases of Bitcoin Core or previous external software will not be able to read the blocksdir with a non-zero XOR-key. +Refer to the `-blocksxor` help for more details. diff --git a/doc/release-notes-29091-29165.md b/doc/release-notes-29091-29165.md index 9c9f8e4e50..e13d29adc6 100644 --- a/doc/release-notes-29091-29165.md +++ b/doc/release-notes-29091-29165.md @@ -1,5 +1,5 @@ Build ----- -GCC 11.1 or later, or Clang 15+ or later, +GCC 11.1 or later, or Clang 16.0 or later, are now required to compile Bitcoin Core. diff --git a/doc/release-notes-29775.md b/doc/release-notes-29775.md new file mode 100644 index 0000000000..6cb3ed3e8d --- /dev/null +++ b/doc/release-notes-29775.md @@ -0,0 +1,10 @@ +Testnet4/BIP94 support +----- + +Support for Testnet4 as specified in [BIP94](https://github.com/bitcoin/bips/blob/master/bip-0094.mediawiki) +has been added. The network can be selected with the `-testnet4` option and +the section header is also named `[testnet4]`. + +While the intention is to phase out support for Testnet3 in an upcoming +version, support for it is still available via the known options in this +release. diff --git a/doc/release-notes-30212.md b/doc/release-notes-30212.md new file mode 100644 index 0000000000..cc4ea59b7f --- /dev/null +++ b/doc/release-notes-30212.md @@ -0,0 +1,8 @@ +RPC +--- + +- Previously when using the `sendrawtransaction` rpc and specifying outputs + that are already in the UXTO set an RPC error code `-27` with RPC error + text "Transaction already in block chain" was returned in response. + The help text has been updated to "Transaction outputs already in utxo set" + to more accurately describe the source of the issue. diff --git a/doc/release-notes-30275.md b/doc/release-notes-30275.md new file mode 100644 index 0000000000..2fcaef17c8 --- /dev/null +++ b/doc/release-notes-30275.md @@ -0,0 +1,7 @@ +RPC +--- + +- The default mode for the `estimatesmartfee` RPC has been updated from `conservative` to `economical`. + which is expected to reduce overestimation for many users, particularly if Replace-by-Fee is an option. + For users that require high confidence in their fee estimates at the cost of potentially overestimating, + the `conservative` mode remains available. diff --git a/doc/release-notes-30352.md b/doc/release-notes-30352.md new file mode 100644 index 0000000000..b67577a466 --- /dev/null +++ b/doc/release-notes-30352.md @@ -0,0 +1,10 @@ +P2P and network changes +----------------------- + +- Pay To Anchor(P2A) is a new standard witness output type for spending, + a newly recognised output template. This allows for key-less anchor + outputs, with compact spending conditions for additional efficiencies on + top of an equivalent `sh(OP_TRUE)` output, in addition to the txid stability + of the spending transaction. + N.B. propagation of this output spending on the network will be limited + until a sufficient number of nodes on the network adopt this upgrade. diff --git a/doc/release-notes-30482.md b/doc/release-notes-30482.md new file mode 100644 index 0000000000..fb625c2fa9 --- /dev/null +++ b/doc/release-notes-30482.md @@ -0,0 +1,6 @@ +Updated REST APIs +----------------- +- Parameter validation for `/rest/getutxos` has been improved by rejecting + truncated or overly large txids and malformed outpoint indices by raising an + HTTP_BAD_REQUEST "Parse error". Previously, these malformed requests would be + silently handled. (#30482, #30444) diff --git a/doc/release-notes-30493.md b/doc/release-notes-30493.md new file mode 100644 index 0000000000..98afbcc7d1 --- /dev/null +++ b/doc/release-notes-30493.md @@ -0,0 +1,4 @@ +Full Replace-By-Fee +=================== + +`mempoolfullrbf=1` is now set by default. diff --git a/doc/release-notes/release-notes-26.2.md b/doc/release-notes/release-notes-26.2.md new file mode 100644 index 0000000000..67d8512dd0 --- /dev/null +++ b/doc/release-notes/release-notes-26.2.md @@ -0,0 +1,94 @@ +26.2 Release Notes +================== + +Bitcoin Core version 26.2 is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-26.2/> + +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 11.0+, 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. + +Notable changes +=============== + +### Script + +- #29853: sign: don't assume we are parsing a sane TapMiniscript + +### P2P and network changes + +- #29691: Change Luke Dashjr seed to dashjr-list-of-p2p-nodes.us +- #30085: p2p: detect addnode cjdns peers in GetAddedNodeInfo() + +### RPC + +- #29869: rpc, bugfix: Enforce maximum value for setmocktime +- #28554: bugfix: throw an error if an invalid parameter is passed to getnetworkhashps RPC +- #30094: rpc: move UniValue in blockToJSON +- #29870: rpc: Reword SighashFromStr error message + +### Build + +- #29747: depends: fix mingw-w64 Qt DEBUG=1 build +- #29985: depends: Fix build of Qt for 32-bit platforms with recent glibc +- #30151: depends: Fetch miniupnpc sources from an alternative website +- #30283: upnp: fix build with miniupnpc 2.2.8 + +### Misc + +- #29776: ThreadSanitizer: Fix #29767 +- #29856: ci: Bump s390x to ubuntu:24.04 +- #29764: doc: Suggest installing dev packages for debian/ubuntu qt5 build +- #30149: contrib: Renew Windows code signing certificate + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Antoine Poinsot +- Ava Chow +- Cory Fields +- dergoegge +- fanquake +- glozow +- Hennadii Stepanov +- Jameson Lopp +- jonatack +- laanwj +- Luke Dashjr +- MarcoFalke +- nanlour +- willcl-ark + +As well as to everyone that helped with translations on +[Transifex](https://www.transifex.com/bitcoin/bitcoin/). diff --git a/doc/release-process.md b/doc/release-process.md index 1e6d49100e..fa2c53eb0c 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -311,13 +311,15 @@ Both variables are used as a guideline for how much space the user needs on thei Note that all values should be taken from a **fully synced** node and have an overhead of 5-10% added on top of its base value. To calculate `m_assumed_blockchain_size`, take the size in GiB of these directories: -- For `mainnet` -> the data directory, excluding the `/testnet3`, `/signet`, and `/regtest` directories and any overly large files, e.g. a huge `debug.log` +- For `mainnet` -> the data directory, excluding the `/testnet3`, `/testnet4`, `/signet`, and `/regtest` directories and any overly large files, e.g. a huge `debug.log` - For `testnet` -> `/testnet3` +- For `testnet4` -> `/testnet4` - For `signet` -> `/signet` To calculate `m_assumed_chain_state_size`, take the size in GiB of these directories: - For `mainnet` -> `/chainstate` - For `testnet` -> `/testnet3/chainstate` +- For `testnet4` -> `/testnet4/chainstate` - For `signet` -> `/signet/chainstate` Notes: diff --git a/doc/tor.md b/doc/tor.md index 65aa3ece02..9560dc29eb 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -193,7 +193,7 @@ In a typical situation, where you're only reachable via Tor, this should suffice listen on all devices and another node could establish a clearnet connection, when knowing your address. To mitigate this, additionally bind the address of your Tor proxy: - ./bitcoind ... -bind=127.0.0.1 + ./bitcoind ... -bind=127.0.0.1:8334=onion If you don't care too much about hiding your node, and want to be reachable on IPv4 as well, use `discover` instead: diff --git a/src/.clang-tidy b/src/.clang-tidy index 61adce1d50..3569dd04b1 100644 --- a/src/.clang-tidy +++ b/src/.clang-tidy @@ -6,10 +6,12 @@ bugprone-move-forwarding-reference, bugprone-string-constructor, bugprone-use-after-move, bugprone-lambda-function-name, +bugprone-unhandled-self-assignment, misc-unused-using-decls, misc-no-recursion, modernize-use-default-member-init, modernize-use-emplace, +modernize-use-equals-default, modernize-use-noexcept, modernize-use-nullptr, performance-*, @@ -23,8 +25,10 @@ readability-const-return-type, readability-redundant-declaration, readability-redundant-string-init, ' +HeaderFilterRegex: '.' WarningsAsErrors: '*' CheckOptions: - key: performance-move-const-arg.CheckTriviallyCopyableMove value: false -HeaderFilterRegex: '.' + - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField + value: false diff --git a/src/Makefile.am b/src/Makefile.am index 183d196a7b..1ccb5332c4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,15 +51,15 @@ LIBBITCOIN_CRYPTO = $(LIBBITCOIN_CRYPTO_BASE) if ENABLE_SSE41 LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.la LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41) +if ENABLE_X86_SHANI +LIBBITCOIN_CRYPTO_X86_SHANI = crypto/libbitcoin_crypto_x86_shani.la +LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_X86_SHANI) +endif endif if ENABLE_AVX2 LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.la LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2) endif -if ENABLE_X86_SHANI -LIBBITCOIN_CRYPTO_X86_SHANI = crypto/libbitcoin_crypto_x86_shani.la -LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_X86_SHANI) -endif if ENABLE_ARM_SHANI LIBBITCOIN_CRYPTO_ARM_SHANI = crypto/libbitcoin_crypto_arm_shani.la LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_ARM_SHANI) @@ -132,6 +132,7 @@ BITCOIN_CORE_H = \ chainparamsseeds.h \ checkqueue.h \ clientversion.h \ + cluster_linearize.h \ coins.h \ common/args.h \ common/bloom.h \ @@ -195,7 +196,6 @@ BITCOIN_CORE_H = \ kernel/mempool_removal_reason.h \ kernel/messagestartchars.h \ kernel/notifications_interface.h \ - kernel/validation_cache_sizes.h \ kernel/warning.h \ key.h \ key_io.h \ @@ -240,7 +240,6 @@ BITCOIN_CORE_H = \ node/txreconciliation.h \ node/types.h \ node/utxo_snapshot.h \ - node/validation_cache_args.h \ node/warnings.h \ noui.h \ outputtype.h \ @@ -258,7 +257,6 @@ BITCOIN_CORE_H = \ random.h \ randomenv.h \ rest.h \ - reverse_iterator.h \ rpc/blockchain.h \ rpc/client.h \ rpc/mempool.h \ @@ -445,7 +443,6 @@ libbitcoin_node_a_SOURCES = \ node/transaction.cpp \ node/txreconciliation.cpp \ node/utxo_snapshot.cpp \ - node/validation_cache_args.cpp \ node/warnings.cpp \ noui.cpp \ policy/fees.cpp \ @@ -625,7 +622,7 @@ crypto_libbitcoin_crypto_x86_shani_la_LDFLAGS = $(AM_LDFLAGS) -static crypto_libbitcoin_crypto_x86_shani_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -static crypto_libbitcoin_crypto_x86_shani_la_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_x86_shani_la_CXXFLAGS += $(X86_SHANI_CXXFLAGS) -crypto_libbitcoin_crypto_x86_shani_la_CPPFLAGS += -DENABLE_X86_SHANI +crypto_libbitcoin_crypto_x86_shani_la_CPPFLAGS += -DENABLE_SSE41 -DENABLE_X86_SHANI crypto_libbitcoin_crypto_x86_shani_la_SOURCES = crypto/sha256_x86_shani.cpp # See explanation for -static in crypto_libbitcoin_crypto_base_la's LDFLAGS and @@ -710,7 +707,6 @@ libbitcoin_common_a_SOURCES = \ outputtype.cpp \ policy/feerate.cpp \ policy/policy.cpp \ - policy/truc_policy.cpp \ protocol.cpp \ psbt.cpp \ rpc/external_signer.cpp \ diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 2ba72c9e76..fe6333d8c0 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -25,6 +25,7 @@ bench_bench_bitcoin_SOURCES = \ bench/checkblock.cpp \ bench/checkblockindex.cpp \ bench/checkqueue.cpp \ + bench/cluster_linearize.cpp \ bench/crypto_hash.cpp \ bench/data.cpp \ bench/data.h \ @@ -49,10 +50,12 @@ bench_bench_bitcoin_SOURCES = \ bench/poly1305.cpp \ bench/pool.cpp \ bench/prevector.cpp \ + bench/random.cpp \ bench/readblock.cpp \ bench/rollingbloom.cpp \ bench/rpc_blockchain.cpp \ bench/rpc_mempool.cpp \ + bench/sign_transaction.cpp \ bench/streams_findbyte.cpp \ bench/strencodings.cpp \ bench/util_time.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 633d0776f5..c396cc2ebf 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -83,7 +83,9 @@ BITCOIN_TESTS =\ test/bloom_tests.cpp \ test/bswap_tests.cpp \ test/checkqueue_tests.cpp \ + test/cluster_linearize_tests.cpp \ test/coins_tests.cpp \ + test/coinscachepair_tests.cpp \ test/coinstatsindex_tests.cpp \ test/common_url_tests.cpp \ test/compilerbug_tests.cpp \ @@ -173,8 +175,7 @@ BITCOIN_TESTS =\ test/validation_flush_tests.cpp \ test/validation_tests.cpp \ test/validationinterface_tests.cpp \ - test/versionbits_tests.cpp \ - test/xoroshiro128plusplus_tests.cpp + test/versionbits_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ @@ -298,11 +299,13 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/bitset.cpp \ test/fuzz/block.cpp \ test/fuzz/block_header.cpp \ + test/fuzz/block_index.cpp \ test/fuzz/blockfilter.cpp \ test/fuzz/bloom_filter.cpp \ test/fuzz/buffered_file.cpp \ test/fuzz/chain.cpp \ test/fuzz/checkqueue.cpp \ + test/fuzz/cluster_linearize.cpp \ test/fuzz/coins_view.cpp \ test/fuzz/coinscache_sim.cpp \ test/fuzz/connman.cpp \ @@ -310,6 +313,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/crypto_aes256.cpp \ test/fuzz/crypto_aes256cbc.cpp \ test/fuzz/crypto_chacha20.cpp \ + test/fuzz/crypto_chacha20poly1305.cpp \ test/fuzz/crypto_common.cpp \ test/fuzz/crypto_diff_fuzz_chacha20.cpp \ test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \ @@ -348,6 +352,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/netaddress.cpp \ test/fuzz/netbase_dns_lookup.cpp \ test/fuzz/node_eviction.cpp \ + test/fuzz/p2p_handshake.cpp \ test/fuzz/p2p_transport_serialization.cpp \ test/fuzz/package_eval.cpp \ test/fuzz/parse_hd_keypath.cpp \ diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index 6a1fd712bd..0c0e849fba 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -10,6 +10,7 @@ EXTRA_LIBRARIES += \ TEST_UTIL_H = \ test/util/blockfilter.h \ test/util/chainstate.h \ + test/util/cluster_linearize.h \ test/util/coins.h \ test/util/index.h \ test/util/json.h \ @@ -23,8 +24,7 @@ TEST_UTIL_H = \ test/util/str.h \ test/util/transaction_utils.h \ test/util/txmempool.h \ - test/util/validation.h \ - test/util/xoroshiro128plusplus.h + test/util/validation.h if ENABLE_WALLET TEST_UTIL_H += wallet/test/util.h diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 4d34c24ba9..e9838d7222 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -53,7 +53,7 @@ template <typename Data> bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data) { // Generate random temporary filename - const uint16_t randv{GetRand<uint16_t>()}; + const uint16_t randv{FastRandomContext().rand<uint16_t>()}; std::string tmpfn = strprintf("%s.%04x", prefix, randv); // open temp output file diff --git a/src/addresstype.cpp b/src/addresstype.cpp index f199d1b479..67e643943d 100644 --- a/src/addresstype.cpp +++ b/src/addresstype.cpp @@ -87,6 +87,10 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) addressRet = tap; return true; } + case TxoutType::ANCHOR: { + addressRet = PayToAnchor(); + return true; + } case TxoutType::WITNESS_UNKNOWN: { addressRet = WitnessUnknown{vSolutions[0][0], vSolutions[1]}; return true; diff --git a/src/addresstype.h b/src/addresstype.h index 0152858bad..93cdf66c5b 100644 --- a/src/addresstype.h +++ b/src/addresstype.h @@ -9,6 +9,7 @@ #include <pubkey.h> #include <script/script.h> #include <uint256.h> +#include <util/check.h> #include <util/hash_type.h> #include <algorithm> @@ -116,6 +117,13 @@ public: } }; +struct PayToAnchor : public WitnessUnknown +{ + PayToAnchor() : WitnessUnknown(1, {0x4e, 0x73}) { + Assume(CScript::IsPayToAnchor(1, {0x4e, 0x73})); + }; +}; + /** * A txout script categorized into standard templates. * * CNoDestination: Optionally a script, no corresponding address. @@ -125,10 +133,11 @@ public: * * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH address) * * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH address) * * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR address) + * * PayToAnchor: TxoutType::ANCHOR destination (P2A address) * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W??? address) * A CTxDestination is the internal data type encoded in a bitcoin address */ -using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown>; +using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown>; /** Check whether a CTxDestination corresponds to one with an address. */ bool IsValidDestination(const CTxDestination& dest); diff --git a/src/addrman.cpp b/src/addrman.cpp index d0b820ee65..054a9bee32 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -776,7 +776,7 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::option const AddrInfo& info{it_found->second}; // With probability GetChance() * chance_factor, return the entry. - if (insecure_rand.randbits(30) < chance_factor * info.GetChance() * (1 << 30)) { + if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) { LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new"); return {info, info.m_last_try}; } diff --git a/src/arith_uint256.h b/src/arith_uint256.h index ba36cebbdc..38b7453034 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -43,8 +43,10 @@ public: base_uint& operator=(const base_uint& b) { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; + if (this != &b) { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } return *this; } @@ -194,6 +196,7 @@ public: return ret; } + /** Numeric ordering (unlike \ref base_blob::Compare) */ int CompareTo(const base_uint& b) const; bool EqualTo(uint64_t b) const; @@ -216,6 +219,7 @@ public: friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } + /** Hex encoding of the number (with the most significant digits first). */ std::string GetHex() const; std::string ToString() const; @@ -240,7 +244,7 @@ public: /** 256-bit unsigned big integer. */ class arith_uint256 : public base_uint<256> { public: - arith_uint256() {} + arith_uint256() = default; arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} arith_uint256(uint64_t b) : base_uint<256>(b) {} diff --git a/src/bech32.cpp b/src/bech32.cpp index d8d31a415c..5694ad54c8 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -19,9 +19,6 @@ namespace typedef std::vector<uint8_t> data; -/** The Bech32 and Bech32m checksum size */ -constexpr size_t CHECKSUM_SIZE = 6; - /** The Bech32 and Bech32m character set for encoding. */ const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; diff --git a/src/bech32.h b/src/bech32.h index fe2a276ae0..33d1ca1935 100644 --- a/src/bech32.h +++ b/src/bech32.h @@ -21,6 +21,9 @@ namespace bech32 { +/** The Bech32 and Bech32m checksum size */ +constexpr size_t CHECKSUM_SIZE = 6; + enum class Encoding { INVALID, //!< Failed decoding diff --git a/src/bench/cluster_linearize.cpp b/src/bench/cluster_linearize.cpp new file mode 100644 index 0000000000..269648f4e2 --- /dev/null +++ b/src/bench/cluster_linearize.cpp @@ -0,0 +1,274 @@ +// Copyright (c) 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 <util/bitset.h> +#include <cluster_linearize.h> + +using namespace cluster_linearize; + +namespace { + +/** Construct a linear graph. These are pessimal for AncestorCandidateFinder, as they maximize + * the number of ancestor set feerate updates. The best ancestor set is always the topmost + * remaining transaction, whose removal requires updating all remaining transactions' ancestor + * set feerates. */ +template<typename SetType> +DepGraph<SetType> MakeLinearGraph(ClusterIndex ntx) +{ + DepGraph<SetType> depgraph; + for (ClusterIndex i = 0; i < ntx; ++i) { + depgraph.AddTransaction({-int32_t(i), 1}); + if (i > 0) depgraph.AddDependency(i - 1, i); + } + return depgraph; +} + +/** Construct a wide graph (one root, with N-1 children that are otherwise unrelated, with + * increasing feerates). These graphs are pessimal for the LIMO step in Linearize, because + * rechunking is needed after every candidate (the last transaction gets picked every time). + */ +template<typename SetType> +DepGraph<SetType> MakeWideGraph(ClusterIndex ntx) +{ + DepGraph<SetType> depgraph; + for (ClusterIndex i = 0; i < ntx; ++i) { + depgraph.AddTransaction({int32_t(i) + 1, 1}); + if (i > 0) depgraph.AddDependency(0, i); + } + return depgraph; +} + +// Construct a difficult graph. These need at least sqrt(2^(n-1)) iterations in the best +// known algorithms (purely empirically determined). +template<typename SetType> +DepGraph<SetType> MakeHardGraph(ClusterIndex ntx) +{ + DepGraph<SetType> depgraph; + for (ClusterIndex i = 0; i < ntx; ++i) { + if (ntx & 1) { + // Odd cluster size. + // + // Mermaid diagram code for the resulting cluster for 11 transactions: + // ```mermaid + // graph BT + // T0["T0: 1/2"];T1["T1: 14/2"];T2["T2: 6/1"];T3["T3: 5/1"];T4["T4: 7/1"]; + // T5["T5: 5/1"];T6["T6: 7/1"];T7["T7: 5/1"];T8["T8: 7/1"];T9["T9: 5/1"]; + // T10["T10: 7/1"]; + // T1-->T0;T1-->T2;T3-->T2;T4-->T3;T4-->T5;T6-->T5;T4-->T7;T8-->T7;T4-->T9;T10-->T9; + // ``` + if (i == 0) { + depgraph.AddTransaction({1, 2}); + } else if (i == 1) { + depgraph.AddTransaction({14, 2}); + depgraph.AddDependency(0, 1); + } else if (i == 2) { + depgraph.AddTransaction({6, 1}); + depgraph.AddDependency(2, 1); + } else if (i == 3) { + depgraph.AddTransaction({5, 1}); + depgraph.AddDependency(2, 3); + } else if ((i & 1) == 0) { + depgraph.AddTransaction({7, 1}); + depgraph.AddDependency(i - 1, i); + } else { + depgraph.AddTransaction({5, 1}); + depgraph.AddDependency(i, 4); + } + } else { + // Even cluster size. + // + // Mermaid diagram code for the resulting cluster for 10 transactions: + // ```mermaid + // graph BT + // T0["T0: 1"];T1["T1: 3"];T2["T2: 1"];T3["T3: 4"];T4["T4: 0"];T5["T5: 4"];T6["T6: 0"]; + // T7["T7: 4"];T8["T8: 0"];T9["T9: 4"]; + // T1-->T0;T2-->T0;T3-->T2;T3-->T4;T5-->T4;T3-->T6;T7-->T6;T3-->T8;T9-->T8; + // ``` + if (i == 0) { + depgraph.AddTransaction({1, 1}); + } else if (i == 1) { + depgraph.AddTransaction({3, 1}); + depgraph.AddDependency(0, 1); + } else if (i == 2) { + depgraph.AddTransaction({1, 1}); + depgraph.AddDependency(0, 2); + } else if (i & 1) { + depgraph.AddTransaction({4, 1}); + depgraph.AddDependency(i - 1, i); + } else { + depgraph.AddTransaction({0, 1}); + depgraph.AddDependency(i, 3); + } + } + } + return depgraph; +} + +/** Benchmark that does search-based candidate finding with 10000 iterations. + * + * Its goal is measuring how much time every additional search iteration in linearization costs. + */ +template<typename SetType> +void BenchLinearizePerIterWorstCase(ClusterIndex ntx, benchmark::Bench& bench) +{ + const auto depgraph = MakeHardGraph<SetType>(ntx); + const auto iter_limit = std::min<uint64_t>(10000, uint64_t{1} << (ntx / 2 - 1)); + uint64_t rng_seed = 0; + bench.batch(iter_limit).unit("iters").run([&] { + SearchCandidateFinder finder(depgraph, rng_seed++); + auto [candidate, iters_performed] = finder.FindCandidateSet(iter_limit, {}); + assert(iters_performed == iter_limit); + }); +} + +/** Benchmark for linearization improvement of a trivial linear graph using just ancestor sort. + * + * Its goal is measuring how much time linearization may take without any search iterations. + * + * If P is the resulting time of BenchLinearizePerIterWorstCase, and N is the resulting time of + * BenchLinearizeNoItersWorstCase*, then an invocation of Linearize with max_iterations=m should + * take no more than roughly N+m*P time. This may however be an overestimate, as the worst cases + * do not coincide (the ones that are worst for linearization without any search happen to be ones + * that do not need many search iterations). + * + * This benchmark exercises a worst case for AncestorCandidateFinder, but for which improvement is + * cheap. + */ +template<typename SetType> +void BenchLinearizeNoItersWorstCaseAnc(ClusterIndex ntx, benchmark::Bench& bench) +{ + const auto depgraph = MakeLinearGraph<SetType>(ntx); + uint64_t rng_seed = 0; + std::vector<ClusterIndex> old_lin(ntx); + for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i; + bench.run([&] { + Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin); + }); +} + +/** Benchmark for linearization improvement of a trivial wide graph using just ancestor sort. + * + * Its goal is measuring how much time improving a linearization may take without any search + * iterations, similar to the previous function. + * + * This benchmark exercises a worst case for improving an existing linearization, but for which + * AncestorCandidateFinder is cheap. + */ +template<typename SetType> +void BenchLinearizeNoItersWorstCaseLIMO(ClusterIndex ntx, benchmark::Bench& bench) +{ + const auto depgraph = MakeWideGraph<SetType>(ntx); + uint64_t rng_seed = 0; + std::vector<ClusterIndex> old_lin(ntx); + for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i; + bench.run([&] { + Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin); + }); +} + +template<typename SetType> +void BenchPostLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench) +{ + DepGraph<SetType> depgraph = MakeWideGraph<SetType>(ntx); + std::vector<ClusterIndex> lin(ntx); + bench.run([&] { + for (ClusterIndex i = 0; i < ntx; ++i) lin[i] = i; + PostLinearize(depgraph, lin); + }); +} + +template<typename SetType> +void BenchMergeLinearizationsWorstCase(ClusterIndex ntx, benchmark::Bench& bench) +{ + DepGraph<SetType> depgraph; + for (ClusterIndex i = 0; i < ntx; ++i) { + depgraph.AddTransaction({i, 1}); + if (i) depgraph.AddDependency(0, i); + } + std::vector<ClusterIndex> lin1; + std::vector<ClusterIndex> lin2; + lin1.push_back(0); + lin2.push_back(0); + for (ClusterIndex i = 1; i < ntx; ++i) { + lin1.push_back(i); + lin2.push_back(ntx - i); + } + bench.run([&] { + MergeLinearizations(depgraph, lin1, lin2); + }); +} + +} // namespace + +static void LinearizePerIter16TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<16>>(16, bench); } +static void LinearizePerIter32TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<32>>(32, bench); } +static void LinearizePerIter48TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<48>>(48, bench); } +static void LinearizePerIter64TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<64>>(64, bench); } +static void LinearizePerIter75TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<75>>(75, bench); } +static void LinearizePerIter99TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<99>>(99, bench); } + +static void LinearizeNoIters16TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<16>>(16, bench); } +static void LinearizeNoIters32TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<32>>(32, bench); } +static void LinearizeNoIters48TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<48>>(48, bench); } +static void LinearizeNoIters64TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<64>>(64, bench); } +static void LinearizeNoIters75TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<75>>(75, bench); } +static void LinearizeNoIters99TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<99>>(99, bench); } + +static void LinearizeNoIters16TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<16>>(16, bench); } +static void LinearizeNoIters32TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<32>>(32, bench); } +static void LinearizeNoIters48TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<48>>(48, bench); } +static void LinearizeNoIters64TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<64>>(64, bench); } +static void LinearizeNoIters75TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<75>>(75, bench); } +static void LinearizeNoIters99TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<99>>(99, bench); } + +static void PostLinearize16TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<16>>(16, bench); } +static void PostLinearize32TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<32>>(32, bench); } +static void PostLinearize48TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<48>>(48, bench); } +static void PostLinearize64TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<64>>(64, bench); } +static void PostLinearize75TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<75>>(75, bench); } +static void PostLinearize99TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<99>>(99, bench); } + +static void MergeLinearizations16TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<16>>(16, bench); } +static void MergeLinearizations32TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<32>>(32, bench); } +static void MergeLinearizations48TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<48>>(48, bench); } +static void MergeLinearizations64TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<64>>(64, bench); } +static void MergeLinearizations75TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<75>>(75, bench); } +static void MergeLinearizations99TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<99>>(99, bench); } + +BENCHMARK(LinearizePerIter16TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizePerIter32TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizePerIter48TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizePerIter64TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizePerIter75TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizePerIter99TxWorstCase, benchmark::PriorityLevel::HIGH); + +BENCHMARK(LinearizeNoIters16TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters32TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters48TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters64TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters75TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters99TxWorstCaseAnc, benchmark::PriorityLevel::HIGH); + +BENCHMARK(LinearizeNoIters16TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters32TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters48TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters64TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters75TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); +BENCHMARK(LinearizeNoIters99TxWorstCaseLIMO, benchmark::PriorityLevel::HIGH); + +BENCHMARK(PostLinearize16TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(PostLinearize32TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(PostLinearize48TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(PostLinearize64TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(PostLinearize75TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(PostLinearize99TxWorstCase, benchmark::PriorityLevel::HIGH); + +BENCHMARK(MergeLinearizations16TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(MergeLinearizations32TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(MergeLinearizations48TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(MergeLinearizations64TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(MergeLinearizations75TxWorstCase, benchmark::PriorityLevel::HIGH); +BENCHMARK(MergeLinearizations99TxWorstCase, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 1685a120b4..2551ff3593 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -196,22 +196,6 @@ static void SipHash_32b(benchmark::Bench& bench) }); } -static void FastRandom_32bit(benchmark::Bench& bench) -{ - FastRandomContext rng(true); - bench.run([&] { - rng.rand32(); - }); -} - -static void FastRandom_1bit(benchmark::Bench& bench) -{ - FastRandomContext rng(true); - bench.run([&] { - rng.randbool(); - }); -} - static void MuHash(benchmark::Bench& bench) { MuHash3072 acc; @@ -274,8 +258,6 @@ BENCHMARK(SHA256D64_1024_STANDARD, benchmark::PriorityLevel::HIGH); BENCHMARK(SHA256D64_1024_SSE4, benchmark::PriorityLevel::HIGH); BENCHMARK(SHA256D64_1024_AVX2, benchmark::PriorityLevel::HIGH); BENCHMARK(SHA256D64_1024_SHANI, 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); diff --git a/src/bench/logging.cpp b/src/bench/logging.cpp index c97c4e151b..8a745a0ba7 100644 --- a/src/bench/logging.cpp +++ b/src/bench/logging.cpp @@ -20,7 +20,7 @@ static void Logging(benchmark::Bench& bench, const std::vector<const char*>& ext TestingSetup test_setup{ ChainType::REGTEST, - extra_args, + {.extra_args = extra_args}, }; bench.run([&] { log(); }); diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index fe3e204fb3..3c82f55c19 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -106,7 +106,7 @@ static void ComplexMemPool(benchmark::Bench& bench) static void MempoolCheck(benchmark::Bench& bench) { FastRandomContext det_rand{true}; - auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(ChainType::REGTEST, {"-checkmempool=1"}); + auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(ChainType::REGTEST, {.extra_args = {"-checkmempool=1"}}); CTxMemPool& pool = *testing_setup.get()->m_node.mempool; LOCK2(cs_main, pool.cs); testing_setup->PopulateMempool(det_rand, 400, true); diff --git a/src/bench/random.cpp b/src/bench/random.cpp new file mode 100644 index 0000000000..cff215d5a7 --- /dev/null +++ b/src/bench/random.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 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 <random.h> + +#include <cstdint> +#include <numeric> + +namespace { + +template<typename RNG> +void BenchRandom_rand64(benchmark::Bench& bench, RNG&& rng) noexcept +{ + bench.batch(1).unit("number").run([&] { + rng.rand64(); + }); +} + +template<typename RNG> +void BenchRandom_rand32(benchmark::Bench& bench, RNG&& rng) noexcept +{ + bench.batch(1).unit("number").run([&] { + rng.rand32(); + }); +} + +template<typename RNG> +void BenchRandom_randbool(benchmark::Bench& bench, RNG&& rng) noexcept +{ + bench.batch(1).unit("number").run([&] { + rng.randbool(); + }); +} + +template<typename RNG> +void BenchRandom_randbits(benchmark::Bench& bench, RNG&& rng) noexcept +{ + bench.batch(64).unit("number").run([&] { + for (int i = 1; i <= 64; ++i) { + rng.randbits(i); + } + }); +} + +template<int RANGE, typename RNG> +void BenchRandom_randrange(benchmark::Bench& bench, RNG&& rng) noexcept +{ + bench.batch(RANGE).unit("number").run([&] { + for (int i = 1; i <= RANGE; ++i) { + rng.randrange(i); + } + }); +} + +template<int RANGE, typename RNG> +void BenchRandom_stdshuffle(benchmark::Bench& bench, RNG&& rng) noexcept +{ + uint64_t data[RANGE]; + std::iota(std::begin(data), std::end(data), uint64_t(0)); + bench.batch(RANGE).unit("number").run([&] { + std::shuffle(std::begin(data), std::end(data), rng); + }); +} + +void FastRandom_rand64(benchmark::Bench& bench) { BenchRandom_rand64(bench, FastRandomContext(true)); } +void FastRandom_rand32(benchmark::Bench& bench) { BenchRandom_rand32(bench, FastRandomContext(true)); } +void FastRandom_randbool(benchmark::Bench& bench) { BenchRandom_randbool(bench, FastRandomContext(true)); } +void FastRandom_randbits(benchmark::Bench& bench) { BenchRandom_randbits(bench, FastRandomContext(true)); } +void FastRandom_randrange100(benchmark::Bench& bench) { BenchRandom_randrange<100>(bench, FastRandomContext(true)); } +void FastRandom_randrange1000(benchmark::Bench& bench) { BenchRandom_randrange<1000>(bench, FastRandomContext(true)); } +void FastRandom_randrange1000000(benchmark::Bench& bench) { BenchRandom_randrange<1000000>(bench, FastRandomContext(true)); } +void FastRandom_stdshuffle100(benchmark::Bench& bench) { BenchRandom_stdshuffle<100>(bench, FastRandomContext(true)); } + +void InsecureRandom_rand64(benchmark::Bench& bench) { BenchRandom_rand64(bench, InsecureRandomContext(251438)); } +void InsecureRandom_rand32(benchmark::Bench& bench) { BenchRandom_rand32(bench, InsecureRandomContext(251438)); } +void InsecureRandom_randbool(benchmark::Bench& bench) { BenchRandom_randbool(bench, InsecureRandomContext(251438)); } +void InsecureRandom_randbits(benchmark::Bench& bench) { BenchRandom_randbits(bench, InsecureRandomContext(251438)); } +void InsecureRandom_randrange100(benchmark::Bench& bench) { BenchRandom_randrange<100>(bench, InsecureRandomContext(251438)); } +void InsecureRandom_randrange1000(benchmark::Bench& bench) { BenchRandom_randrange<1000>(bench, InsecureRandomContext(251438)); } +void InsecureRandom_randrange1000000(benchmark::Bench& bench) { BenchRandom_randrange<1000000>(bench, InsecureRandomContext(251438)); } +void InsecureRandom_stdshuffle100(benchmark::Bench& bench) { BenchRandom_stdshuffle<100>(bench, InsecureRandomContext(251438)); } + +} // namespace + +BENCHMARK(FastRandom_rand64, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_rand32, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_randbool, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_randbits, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_randrange100, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_randrange1000, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_randrange1000000, benchmark::PriorityLevel::HIGH); +BENCHMARK(FastRandom_stdshuffle100, benchmark::PriorityLevel::HIGH); + +BENCHMARK(InsecureRandom_rand64, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_rand32, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_randbool, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_randbits, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_randrange100, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_randrange1000, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_randrange1000000, benchmark::PriorityLevel::HIGH); +BENCHMARK(InsecureRandom_stdshuffle100, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/sign_transaction.cpp b/src/bench/sign_transaction.cpp new file mode 100644 index 0000000000..6f28f581af --- /dev/null +++ b/src/bench/sign_transaction.cpp @@ -0,0 +1,99 @@ +// 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 <bench/bench.h> +#include <addresstype.h> +#include <coins.h> +#include <key.h> +#include <primitives/transaction.h> +#include <pubkey.h> +#include <script/interpreter.h> +#include <script/script.h> +#include <script/sign.h> +#include <uint256.h> +#include <test/util/random.h> +#include <util/translation.h> + +enum class InputType { + P2WPKH, // segwitv0, witness-pubkey-hash (ECDSA signature) + P2TR, // segwitv1, taproot key-path spend (Schnorr signature) +}; + +static void SignTransactionSingleInput(benchmark::Bench& bench, InputType input_type) +{ + ECC_Context ecc_context{}; + + FlatSigningProvider keystore; + std::vector<CScript> prev_spks; + + // Create a bunch of keys / UTXOs to avoid signing with the same key repeatedly + for (int i = 0; i < 32; i++) { + CKey privkey = GenerateRandomKey(); + CPubKey pubkey = privkey.GetPubKey(); + CKeyID key_id = pubkey.GetID(); + keystore.keys.emplace(key_id, privkey); + keystore.pubkeys.emplace(key_id, pubkey); + + // Create specified locking script type + CScript prev_spk; + switch (input_type) { + case InputType::P2WPKH: prev_spk = GetScriptForDestination(WitnessV0KeyHash(pubkey)); break; + case InputType::P2TR: prev_spk = GetScriptForDestination(WitnessV1Taproot(XOnlyPubKey{pubkey})); break; + default: assert(false); + } + prev_spks.push_back(prev_spk); + } + + // Simple 1-input tx with artificial outpoint + // (note that for the purpose of signing with SIGHASH_ALL we don't need any outputs) + COutPoint prevout{/*hashIn=*/Txid::FromUint256(uint256::ONE), /*nIn=*/1337}; + CMutableTransaction unsigned_tx; + unsigned_tx.vin.emplace_back(prevout); + + // Benchmark. + int iter = 0; + bench.minEpochIterations(100).run([&] { + CMutableTransaction tx{unsigned_tx}; + std::map<COutPoint, Coin> coins; + CScript prev_spk = prev_spks[(iter++) % prev_spks.size()]; + coins[prevout] = Coin(CTxOut(10000, prev_spk), /*nHeightIn=*/100, /*fCoinBaseIn=*/false); + std::map<int, bilingual_str> input_errors; + bool complete = SignTransaction(tx, &keystore, coins, SIGHASH_ALL, input_errors); + assert(complete); + }); +} + +static void SignTransactionECDSA(benchmark::Bench& bench) { SignTransactionSingleInput(bench, InputType::P2WPKH); } +static void SignTransactionSchnorr(benchmark::Bench& bench) { SignTransactionSingleInput(bench, InputType::P2TR); } + +static void SignSchnorrTapTweakBenchmark(benchmark::Bench& bench, bool use_null_merkle_root) +{ + ECC_Context ecc_context{}; + + auto key = GenerateRandomKey(); + auto msg = InsecureRand256(); + auto merkle_root = use_null_merkle_root ? uint256() : InsecureRand256(); + auto aux = InsecureRand256(); + std::vector<unsigned char> sig(64); + + bench.minEpochIterations(100).run([&] { + bool success = key.SignSchnorr(msg, sig, &merkle_root, aux); + assert(success); + }); +} + +static void SignSchnorrWithMerkleRoot(benchmark::Bench& bench) +{ + SignSchnorrTapTweakBenchmark(bench, /*use_null_merkle_root=*/false); +} + +static void SignSchnorrWithNullMerkleRoot(benchmark::Bench& bench) +{ + SignSchnorrTapTweakBenchmark(bench, /*use_null_merkle_root=*/true); +} + +BENCHMARK(SignTransactionECDSA, benchmark::PriorityLevel::HIGH); +BENCHMARK(SignTransactionSchnorr, benchmark::PriorityLevel::HIGH); +BENCHMARK(SignSchnorrWithMerkleRoot, benchmark::PriorityLevel::HIGH); +BENCHMARK(SignSchnorrWithNullMerkleRoot, benchmark::PriorityLevel::HIGH); diff --git a/src/bench/wallet_create.cpp b/src/bench/wallet_create.cpp index 5c0557bf6f..1adced1e99 100644 --- a/src/bench/wallet_create.cpp +++ b/src/bench/wallet_create.cpp @@ -42,7 +42,7 @@ static void WalletCreate(benchmark::Bench& bench, bool encrypted) // Release wallet RemoveWallet(context, wallet, /*load_on_start=*/ std::nullopt); - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); fs::remove_all(wallet_path); }); } diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index ecbdcd48bb..ebe013b638 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -15,11 +15,11 @@ #include <kernel/chainstatemanager_opts.h> #include <kernel/checks.h> #include <kernel/context.h> -#include <kernel/validation_cache_sizes.h> #include <kernel/warning.h> #include <consensus/validation.h> #include <core_io.h> +#include <logging.h> #include <node/blockstorage.h> #include <node/caches.h> #include <node/chainstate.h> @@ -42,6 +42,12 @@ int main(int argc, char* argv[]) { + // We do not enable logging for this app, so explicitly disable it. + // To enable logging instead, replace with: + // LogInstance().m_print_to_console = true; + // LogInstance().StartLogging(); + LogInstance().DisableLogging(); + // SETUP: Argument parsing and handling if (argc != 2) { std::cerr @@ -63,13 +69,6 @@ int main(int argc, char* argv[]) // properly assert(kernel::SanityChecks(kernel_context)); - // Necessary for CheckInputScripts (eventually called by ProcessNewBlock), - // which will try the script cache first and fall back to actually - // performing the check with the signature cache. - kernel::ValidationCacheSizes validation_cache_sizes{}; - Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes)); - Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes)); - ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()}; class KernelNotifications : public kernel::Notifications diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 44fc273163..934b5fb6dc 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -75,6 +75,7 @@ static void SetupCliArgs(ArgsManager& argsman) const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN); const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET); + const auto testnet4BaseParams = CreateBaseChainParams(ChainType::TESTNET4); const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET); const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST); @@ -98,7 +99,7 @@ static void SetupCliArgs(ArgsManager& argsman) argsman.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 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::OPTIONS); argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS); + argsman.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-rpcwait", "Wait for RPC server to start", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-rpcwaittimeout=<n>", strprintf("Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d)", DEFAULT_WAIT_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); @@ -428,6 +429,8 @@ private: std::string ChainToString() const { switch (gArgs.GetChainType()) { + case ChainType::TESTNET4: + return " testnet4"; case ChainType::TESTNET: return " testnet"; case ChainType::SIGNET: diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 89faa0123a..89c03c1647 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -264,8 +264,8 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu throw std::runtime_error("TX input missing separator"); // extract and validate TXID - uint256 txid; - if (!ParseHashStr(vStrInputParts[0], txid)) { + auto txid{Txid::FromHex(vStrInputParts[0])}; + if (!txid) { throw std::runtime_error("invalid TX input txid"); } @@ -285,7 +285,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu } // append to transaction input list - CTxIn txin(Txid::FromUint256(txid), vout, CScript(), nSequenceIn); + CTxIn txin(*txid, vout, CScript(), nSequenceIn); tx.vin.push_back(txin); } @@ -625,8 +625,8 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) if (!prevOut.checkObject(types)) throw std::runtime_error("prevtxs internal object typecheck fail"); - uint256 txid; - if (!ParseHashStr(prevOut["txid"].get_str(), txid)) { + auto txid{Txid::FromHex(prevOut["txid"].get_str())}; + if (!txid) { throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')"); } @@ -634,7 +634,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) if (nOut < 0) throw std::runtime_error("vout cannot be negative"); - COutPoint out(Txid::FromUint256(txid), nOut); + COutPoint out(*txid, nOut); std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index b6f5c3f15d..7d030abe97 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -69,7 +69,7 @@ static std::optional<int> WalletAppInit(ArgsManager& args, int argc, char* argv[ strUsage += "\n" "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n" "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n" - "To change the target wallet, use the -datadir, -wallet and -regtest/-signet/-testnet arguments.\n\n" + "To change the target wallet, use the -datadir, -wallet and -regtest/-signet/-testnet/-testnet4 arguments.\n\n" "Usage:\n" " bitcoin-wallet [options] <command>\n"; strUsage += "\n" + args.GetHelpMessage(); diff --git a/src/blockencodings.h b/src/blockencodings.h index bc1d08ba5a..c92aa05e80 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -59,7 +59,7 @@ public: uint256 blockhash; std::vector<CTransactionRef> txn; - BlockTransactions() {} + BlockTransactions() = default; explicit BlockTransactions(const BlockTransactionsRequest& req) : blockhash(req.blockhash), txn(req.indexes.size()) {} @@ -109,7 +109,7 @@ public: /** * Dummy for deserialization */ - CBlockHeaderAndShortTxIDs() {} + CBlockHeaderAndShortTxIDs() = default; /** * @param[in] nonce This should be randomly generated, and is used for the siphash secret key diff --git a/src/chain.h b/src/chain.h index bb70dbd8bc..c46392c535 100644 --- a/src/chain.h +++ b/src/chain.h @@ -66,7 +66,7 @@ public: READWRITE(VARINT(obj.nTimeLast)); } - CBlockFileInfo() {} + CBlockFileInfo() = default; std::string ToString() const; @@ -102,7 +102,7 @@ enum BlockStatus : uint32_t { * * If a block's validity is at least VALID_TRANSACTIONS, CBlockIndex::nTx will be set. If a block and all previous * blocks back to the genesis block or an assumeutxo snapshot block are at least VALID_TRANSACTIONS, - * CBlockIndex::nChainTx will be set. + * CBlockIndex::m_chain_tx_count will be set. */ BLOCK_VALID_TRANSACTIONS = 3, @@ -173,8 +173,7 @@ public: //! This value will be non-zero if this block and all previous blocks back //! to the genesis block or an assumeutxo snapshot block have reached the //! VALID_TRANSACTIONS level. - //! Change to 64-bit type before 2024 (assuming worst case of 60 byte transactions). - unsigned int nChainTx{0}; + uint64_t m_chain_tx_count{0}; //! Verification status of this block. See enum BlockStatus //! @@ -254,10 +253,10 @@ public: * Does not imply the transactions are consensus-valid (ConnectTip might fail) * Does not imply the transactions are still stored on disk. (IsBlockPruned might return true) * - * Note that this will be true for the snapshot base block, if one is loaded, since its nChainTx value will have + * Note that this will be true for the snapshot base block, if one is loaded, since its m_chain_tx_count value will have * been set manually based on the related AssumeutxoData entry. */ - bool HaveNumChainTxs() const { return nChainTx != 0; } + bool HaveNumChainTxs() const { return m_chain_tx_count != 0; } NodeSeconds Time() const { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5d4401b719..68319e8e8b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -115,6 +115,8 @@ std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, c return CChainParams::Main(); case ChainType::TESTNET: return CChainParams::TestNet(); + case ChainType::TESTNET4: + return CChainParams::TestNet4(); case ChainType::SIGNET: { auto opts = CChainParams::SigNetOptions{}; ReadSigNetArgs(args, opts); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 8cbf9e85e0..aadd04e509 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -13,11 +13,12 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) { - argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: " LIST_CHAIN_NAMES, ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " "This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-testnet", "Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed in an upcoming release. Consider moving to testnet4 now by using -testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-testnet4", "Use the testnet4 chain. Equivalent to -chain=testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); @@ -33,7 +34,7 @@ const CBaseChainParams& BaseParams() } /** - * Port numbers for incoming Tor connections (8334, 18334, 38334, 18445) have + * Port numbers for incoming Tor connections (8334, 18334, 38334, 48334, 18445) have * been chosen arbitrarily to keep ranges of used ports tight. */ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const ChainType chain) @@ -43,6 +44,8 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const ChainType chain) return std::make_unique<CBaseChainParams>("", 8332, 8334); case ChainType::TESTNET: return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334); + case ChainType::TESTNET4: + return std::make_unique<CBaseChainParams>("testnet4", 48332, 48334); case ChainType::SIGNET: return std::make_unique<CBaseChainParams>("signet", 38332, 38334); case ChainType::REGTEST: diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index ea933d1ca8..c75a70cb96 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -7,6 +7,7 @@ #include <util/chaintype.h> +#include <cstdint> #include <memory> #include <string> @@ -52,4 +53,7 @@ const CBaseChainParams& BaseParams(); /** Sets the params returned by Params() to those for the given chain. */ void SelectBaseParams(const ChainType chain); +/** List of possible chain / network names */ +#define LIST_CHAIN_NAMES "main, test, testnet4, signet, regtest" + #endif // BITCOIN_CHAINPARAMSBASE_H diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 554d0cae5a..2a7e52316a 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -1786,4 +1786,16 @@ static const uint8_t chainparams_seed_test[] = { 0x04,0x20,0xbd,0x0e,0xc8,0x73,0x43,0xa7,0xc6,0x25,0x15,0xcf,0x3e,0x23,0xa8,0xb0,0xbf,0xe8,0x20,0xa7,0xec,0x2a,0xf6,0x37,0x6c,0x60,0x5e,0x4d,0xed,0xf4,0xb1,0xef,0xf7,0xb2,0x47,0x9d, 0x04,0x20,0xc8,0x88,0xfe,0x71,0x5f,0xa3,0x6c,0x96,0x6a,0xd7,0x9e,0x38,0x84,0x9f,0x44,0xe1,0x6b,0xdc,0x98,0x31,0xad,0x96,0x29,0xe7,0x00,0x83,0x63,0x03,0xae,0x69,0x2e,0x63,0x47,0x9d, }; + +static const uint8_t chainparams_seed_testnet4[] = { + 0x01,0x04,0x39,0x80,0xb0,0xa3,0xbc,0xcd, + 0x01,0x04,0x33,0x9e,0xf8,0x08,0xbc,0xcd, + 0x01,0x04,0x5f,0xd9,0x49,0xa2,0xbc,0xcd, + 0x01,0x04,0x12,0xbd,0x9c,0x66,0xbc,0xcd, + 0x01,0x04,0x67,0x63,0xab,0xd4,0xbc,0xcd, + 0x01,0x04,0x52,0x43,0x66,0x0f,0xbc,0xcd, + 0x01,0x04,0x58,0x63,0xf8,0x32,0xbc,0xcd, + 0x01,0x04,0x67,0xa5,0xc0,0xd2,0xbc,0xcd, + 0x01,0x04,0x12,0xc9,0xcf,0x37,0xbc,0xcd, +}; #endif // BITCOIN_CHAINPARAMSSEEDS_H diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h new file mode 100644 index 0000000000..607ae681d2 --- /dev/null +++ b/src/cluster_linearize.h @@ -0,0 +1,1052 @@ +// Copyright (c) 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_CLUSTER_LINEARIZE_H +#define BITCOIN_CLUSTER_LINEARIZE_H + +#include <algorithm> +#include <numeric> +#include <optional> +#include <stdint.h> +#include <vector> +#include <utility> + +#include <random.h> +#include <span.h> +#include <util/feefrac.h> +#include <util/vecdeque.h> + +namespace cluster_linearize { + +/** Data type to represent cluster input. + * + * cluster[i].first is tx_i's fee and size. + * cluster[i].second[j] is true iff tx_i spends one or more of tx_j's outputs. + */ +template<typename SetType> +using Cluster = std::vector<std::pair<FeeFrac, SetType>>; + +/** Data type to represent transaction indices in clusters. */ +using ClusterIndex = uint32_t; + +/** Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors, + * descendants). */ +template<typename SetType> +class DepGraph +{ + /** Information about a single transaction. */ + struct Entry + { + /** Fee and size of transaction itself. */ + FeeFrac feerate; + /** All ancestors of the transaction (including itself). */ + SetType ancestors; + /** All descendants of the transaction (including itself). */ + SetType descendants; + + /** Equality operator (primarily for for testing purposes). */ + friend bool operator==(const Entry&, const Entry&) noexcept = default; + + /** Construct an empty entry. */ + Entry() noexcept = default; + /** Construct an entry with a given feerate, ancestor set, descendant set. */ + Entry(const FeeFrac& f, const SetType& a, const SetType& d) noexcept : feerate(f), ancestors(a), descendants(d) {} + }; + + /** Data for each transaction, in the same order as the Cluster it was constructed from. */ + std::vector<Entry> entries; + +public: + /** Equality operator (primarily for testing purposes). */ + friend bool operator==(const DepGraph&, const DepGraph&) noexcept = default; + + // Default constructors. + DepGraph() noexcept = default; + DepGraph(const DepGraph&) noexcept = default; + DepGraph(DepGraph&&) noexcept = default; + DepGraph& operator=(const DepGraph&) noexcept = default; + DepGraph& operator=(DepGraph&&) noexcept = default; + + /** Construct a DepGraph object for ntx transactions, with no dependencies. + * + * Complexity: O(N) where N=ntx. + **/ + explicit DepGraph(ClusterIndex ntx) noexcept + { + Assume(ntx <= SetType::Size()); + entries.resize(ntx); + for (ClusterIndex i = 0; i < ntx; ++i) { + entries[i].ancestors = SetType::Singleton(i); + entries[i].descendants = SetType::Singleton(i); + } + } + + /** Construct a DepGraph object given a cluster. + * + * Complexity: O(N^2) where N=cluster.size(). + */ + explicit DepGraph(const Cluster<SetType>& cluster) noexcept : entries(cluster.size()) + { + for (ClusterIndex i = 0; i < cluster.size(); ++i) { + // Fill in fee and size. + entries[i].feerate = cluster[i].first; + // Fill in direct parents as ancestors. + entries[i].ancestors = cluster[i].second; + // Make sure transactions are ancestors of themselves. + entries[i].ancestors.Set(i); + } + + // Propagate ancestor information. + for (ClusterIndex i = 0; i < entries.size(); ++i) { + // At this point, entries[a].ancestors[b] is true iff b is an ancestor of a and there + // is a path from a to b through the subgraph consisting of {a, b} union + // {0, 1, ..., (i-1)}. + SetType to_merge = entries[i].ancestors; + for (ClusterIndex j = 0; j < entries.size(); ++j) { + if (entries[j].ancestors[i]) { + entries[j].ancestors |= to_merge; + } + } + } + + // Fill in descendant information by transposing the ancestor information. + for (ClusterIndex i = 0; i < entries.size(); ++i) { + for (auto j : entries[i].ancestors) { + entries[j].descendants.Set(i); + } + } + } + + /** Get the number of transactions in the graph. Complexity: O(1). */ + auto TxCount() const noexcept { return entries.size(); } + /** Get the feerate of a given transaction i. Complexity: O(1). */ + const FeeFrac& FeeRate(ClusterIndex i) const noexcept { return entries[i].feerate; } + /** Get the mutable feerate of a given transaction i. Complexity: O(1). */ + FeeFrac& FeeRate(ClusterIndex i) noexcept { return entries[i].feerate; } + /** Get the ancestors of a given transaction i. Complexity: O(1). */ + const SetType& Ancestors(ClusterIndex i) const noexcept { return entries[i].ancestors; } + /** Get the descendants of a given transaction i. Complexity: O(1). */ + const SetType& Descendants(ClusterIndex i) const noexcept { return entries[i].descendants; } + + /** Add a new unconnected transaction to this transaction graph (at the end), and return its + * ClusterIndex. + * + * Complexity: O(1) (amortized, due to resizing of backing vector). + */ + ClusterIndex AddTransaction(const FeeFrac& feefrac) noexcept + { + Assume(TxCount() < SetType::Size()); + ClusterIndex new_idx = TxCount(); + entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx)); + return new_idx; + } + + /** Modify this transaction graph, adding a dependency between a specified parent and child. + * + * Complexity: O(N) where N=TxCount(). + **/ + void AddDependency(ClusterIndex parent, ClusterIndex child) noexcept + { + // Bail out if dependency is already implied. + if (entries[child].ancestors[parent]) return; + // To each ancestor of the parent, add as descendants the descendants of the child. + const auto& chl_des = entries[child].descendants; + for (auto anc_of_par : Ancestors(parent)) { + entries[anc_of_par].descendants |= chl_des; + } + // To each descendant of the child, add as ancestors the ancestors of the parent. + const auto& par_anc = entries[parent].ancestors; + for (auto dec_of_chl : Descendants(child)) { + entries[dec_of_chl].ancestors |= par_anc; + } + } + + /** Compute the aggregate feerate of a set of nodes in this graph. + * + * Complexity: O(N) where N=elems.Count(). + **/ + FeeFrac FeeRate(const SetType& elems) const noexcept + { + FeeFrac ret; + for (auto pos : elems) ret += entries[pos].feerate; + return ret; + } + + /** Find some connected component within the subset "todo" of this graph. + * + * Specifically, this finds the connected component which contains the first transaction of + * todo (if any). + * + * Two transactions are considered connected if they are both in `todo`, and one is an ancestor + * of the other in the entire graph (so not just within `todo`), or transitively there is a + * path of transactions connecting them. This does mean that if `todo` contains a transaction + * and a grandparent, but misses the parent, they will still be part of the same component. + * + * Complexity: O(ret.Count()). + */ + SetType FindConnectedComponent(const SetType& todo) const noexcept + { + if (todo.None()) return todo; + auto to_add = SetType::Singleton(todo.First()); + SetType ret; + do { + SetType old = ret; + for (auto add : to_add) { + ret |= Descendants(add); + ret |= Ancestors(add); + } + ret &= todo; + to_add = ret - old; + } while (to_add.Any()); + return ret; + } + + /** Determine if a subset is connected. + * + * Complexity: O(subset.Count()). + */ + bool IsConnected(const SetType& subset) const noexcept + { + return FindConnectedComponent(subset) == subset; + } + + /** Determine if this entire graph is connected. + * + * Complexity: O(TxCount()). + */ + bool IsConnected() const noexcept { return IsConnected(SetType::Fill(TxCount())); } + + /** Append the entries of select to list in a topologically valid order. + * + * Complexity: O(select.Count() * log(select.Count())). + */ + void AppendTopo(std::vector<ClusterIndex>& list, const SetType& select) const noexcept + { + ClusterIndex old_len = list.size(); + for (auto i : select) list.push_back(i); + std::sort(list.begin() + old_len, list.end(), [&](ClusterIndex a, ClusterIndex b) noexcept { + const auto a_anc_count = entries[a].ancestors.Count(); + const auto b_anc_count = entries[b].ancestors.Count(); + if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count; + return a < b; + }); + } +}; + +/** A set of transactions together with their aggregate feerate. */ +template<typename SetType> +struct SetInfo +{ + /** The transactions in the set. */ + SetType transactions; + /** Their combined fee and size. */ + FeeFrac feerate; + + /** Construct a SetInfo for the empty set. */ + SetInfo() noexcept = default; + + /** Construct a SetInfo for a specified set and feerate. */ + SetInfo(const SetType& txn, const FeeFrac& fr) noexcept : transactions(txn), feerate(fr) {} + + /** Construct a SetInfo for a given transaction in a depgraph. */ + explicit SetInfo(const DepGraph<SetType>& depgraph, ClusterIndex pos) noexcept : + transactions(SetType::Singleton(pos)), feerate(depgraph.FeeRate(pos)) {} + + /** Construct a SetInfo for a set of transactions in a depgraph. */ + explicit SetInfo(const DepGraph<SetType>& depgraph, const SetType& txn) noexcept : + transactions(txn), feerate(depgraph.FeeRate(txn)) {} + + /** Add the transactions of other to this SetInfo (no overlap allowed). */ + SetInfo& operator|=(const SetInfo& other) noexcept + { + Assume(!transactions.Overlaps(other.transactions)); + transactions |= other.transactions; + feerate += other.feerate; + return *this; + } + + /** Construct a new SetInfo equal to this, with more transactions added (which may overlap + * with the existing transactions in the SetInfo). */ + [[nodiscard]] SetInfo Add(const DepGraph<SetType>& depgraph, const SetType& txn) const noexcept + { + return {transactions | txn, feerate + depgraph.FeeRate(txn - transactions)}; + } + + /** Swap two SetInfo objects. */ + friend void swap(SetInfo& a, SetInfo& b) noexcept + { + swap(a.transactions, b.transactions); + swap(a.feerate, b.feerate); + } + + /** Permit equality testing. */ + friend bool operator==(const SetInfo&, const SetInfo&) noexcept = default; +}; + +/** Compute the feerates of the chunks of linearization. */ +template<typename SetType> +std::vector<FeeFrac> ChunkLinearization(const DepGraph<SetType>& depgraph, Span<const ClusterIndex> linearization) noexcept +{ + std::vector<FeeFrac> ret; + for (ClusterIndex i : linearization) { + /** The new chunk to be added, initially a singleton. */ + auto new_chunk = depgraph.FeeRate(i); + // As long as the new chunk has a higher feerate than the last chunk so far, absorb it. + while (!ret.empty() && new_chunk >> ret.back()) { + new_chunk += ret.back(); + ret.pop_back(); + } + // Actually move that new chunk into the chunking. + ret.push_back(std::move(new_chunk)); + } + return ret; +} + +/** Data structure encapsulating the chunking of a linearization, permitting removal of subsets. */ +template<typename SetType> +class LinearizationChunking +{ + /** The depgraph this linearization is for. */ + const DepGraph<SetType>& m_depgraph; + + /** The linearization we started from, possibly with removed prefix stripped. */ + Span<const ClusterIndex> m_linearization; + + /** Chunk sets and their feerates, of what remains of the linearization. */ + std::vector<SetInfo<SetType>> m_chunks; + + /** How large a prefix of m_chunks corresponds to removed transactions. */ + ClusterIndex m_chunks_skip{0}; + + /** Which transactions remain in the linearization. */ + SetType m_todo; + + /** Fill the m_chunks variable, and remove the done prefix of m_linearization. */ + void BuildChunks() noexcept + { + // Caller must clear m_chunks. + Assume(m_chunks.empty()); + + // Chop off the initial part of m_linearization that is already done. + while (!m_linearization.empty() && !m_todo[m_linearization.front()]) { + m_linearization = m_linearization.subspan(1); + } + + // Iterate over the remaining entries in m_linearization. This is effectively the same + // algorithm as ChunkLinearization, but supports skipping parts of the linearization and + // keeps track of the sets themselves instead of just their feerates. + for (auto idx : m_linearization) { + if (!m_todo[idx]) continue; + // Start with an initial chunk containing just element idx. + SetInfo add(m_depgraph, idx); + // Absorb existing final chunks into add while they have lower feerate. + while (!m_chunks.empty() && add.feerate >> m_chunks.back().feerate) { + add |= m_chunks.back(); + m_chunks.pop_back(); + } + // Remember new chunk. + m_chunks.push_back(std::move(add)); + } + } + +public: + /** Initialize a LinearizationSubset object for a given length of linearization. */ + explicit LinearizationChunking(const DepGraph<SetType>& depgraph LIFETIMEBOUND, Span<const ClusterIndex> lin LIFETIMEBOUND) noexcept : + m_depgraph(depgraph), m_linearization(lin) + { + // Mark everything in lin as todo still. + for (auto i : m_linearization) m_todo.Set(i); + // Compute the initial chunking. + m_chunks.reserve(depgraph.TxCount()); + BuildChunks(); + } + + /** Determine how many chunks remain in the linearization. */ + ClusterIndex NumChunksLeft() const noexcept { return m_chunks.size() - m_chunks_skip; } + + /** Access a chunk. Chunk 0 is the highest-feerate prefix of what remains. */ + const SetInfo<SetType>& GetChunk(ClusterIndex n) const noexcept + { + Assume(n + m_chunks_skip < m_chunks.size()); + return m_chunks[n + m_chunks_skip]; + } + + /** Remove some subset of transactions from the linearization. */ + void MarkDone(SetType subset) noexcept + { + Assume(subset.Any()); + Assume(subset.IsSubsetOf(m_todo)); + m_todo -= subset; + if (GetChunk(0).transactions == subset) { + // If the newly done transactions exactly match the first chunk of the remainder of + // the linearization, we do not need to rechunk; just remember to skip one + // additional chunk. + ++m_chunks_skip; + // With subset marked done, some prefix of m_linearization will be done now. How long + // that prefix is depends on how many done elements were interspersed with subset, + // but at least as many transactions as there are in subset. + m_linearization = m_linearization.subspan(subset.Count()); + } else { + // Otherwise rechunk what remains of m_linearization. + m_chunks.clear(); + m_chunks_skip = 0; + BuildChunks(); + } + } + + /** Find the shortest intersection between subset and the prefixes of remaining chunks + * of the linearization that has a feerate not below subset's. + * + * This is a crucial operation in guaranteeing improvements to linearizations. If subset has + * a feerate not below GetChunk(0)'s, then moving IntersectPrefixes(subset) to the front of + * (what remains of) the linearization is guaranteed not to make it worse at any point. + * + * See https://delvingbitcoin.org/t/introduction-to-cluster-linearization/1032 for background. + */ + SetInfo<SetType> IntersectPrefixes(const SetInfo<SetType>& subset) const noexcept + { + Assume(subset.transactions.IsSubsetOf(m_todo)); + SetInfo<SetType> accumulator; + // Iterate over all chunks of the remaining linearization. + for (ClusterIndex i = 0; i < NumChunksLeft(); ++i) { + // Find what (if any) intersection the chunk has with subset. + const SetType to_add = GetChunk(i).transactions & subset.transactions; + if (to_add.Any()) { + // If adding that to accumulator makes us hit all of subset, we are done as no + // shorter intersection with higher/equal feerate exists. + accumulator.transactions |= to_add; + if (accumulator.transactions == subset.transactions) break; + // Otherwise update the accumulator feerate. + accumulator.feerate += m_depgraph.FeeRate(to_add); + // If that does result in something better, or something with the same feerate but + // smaller, return that. Even if a longer, higher-feerate intersection exists, it + // does not hurt to return the shorter one (the remainder of the longer intersection + // will generally be found in the next call to Intersect, but even if not, it is not + // required for the improvement guarantee this function makes). + if (!(accumulator.feerate << subset.feerate)) return accumulator; + } + } + return subset; + } +}; + +/** Class encapsulating the state needed to find the best remaining ancestor set. + * + * It is initialized for an entire DepGraph, and parts of the graph can be dropped by calling + * MarkDone. + * + * As long as any part of the graph remains, FindCandidateSet() can be called which will return a + * SetInfo with the highest-feerate ancestor set that remains (an ancestor set is a single + * transaction together with all its remaining ancestors). + */ +template<typename SetType> +class AncestorCandidateFinder +{ + /** Internal dependency graph. */ + const DepGraph<SetType>& m_depgraph; + /** Which transaction are left to include. */ + SetType m_todo; + /** Precomputed ancestor-set feerates (only kept up-to-date for indices in m_todo). */ + std::vector<FeeFrac> m_ancestor_set_feerates; + +public: + /** Construct an AncestorCandidateFinder for a given cluster. + * + * Complexity: O(N^2) where N=depgraph.TxCount(). + */ + AncestorCandidateFinder(const DepGraph<SetType>& depgraph LIFETIMEBOUND) noexcept : + m_depgraph(depgraph), + m_todo{SetType::Fill(depgraph.TxCount())}, + m_ancestor_set_feerates(depgraph.TxCount()) + { + // Precompute ancestor-set feerates. + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + /** The remaining ancestors for transaction i. */ + SetType anc_to_add = m_depgraph.Ancestors(i); + FeeFrac anc_feerate; + // Reuse accumulated feerate from first ancestor, if usable. + Assume(anc_to_add.Any()); + ClusterIndex first = anc_to_add.First(); + if (first < i) { + anc_feerate = m_ancestor_set_feerates[first]; + Assume(!anc_feerate.IsEmpty()); + anc_to_add -= m_depgraph.Ancestors(first); + } + // Add in other ancestors (which necessarily include i itself). + Assume(anc_to_add[i]); + anc_feerate += m_depgraph.FeeRate(anc_to_add); + // Store the result. + m_ancestor_set_feerates[i] = anc_feerate; + } + } + + /** Remove a set of transactions from the set of to-be-linearized ones. + * + * The same transaction may not be MarkDone()'d twice. + * + * Complexity: O(N*M) where N=depgraph.TxCount(), M=select.Count(). + */ + void MarkDone(SetType select) noexcept + { + Assume(select.Any()); + Assume(select.IsSubsetOf(m_todo)); + m_todo -= select; + for (auto i : select) { + auto feerate = m_depgraph.FeeRate(i); + for (auto j : m_depgraph.Descendants(i) & m_todo) { + m_ancestor_set_feerates[j] -= feerate; + } + } + } + + /** Check whether any unlinearized transactions remain. */ + bool AllDone() const noexcept + { + return m_todo.None(); + } + + /** Find the best (highest-feerate, smallest among those in case of a tie) ancestor set + * among the remaining transactions. Requires !AllDone(). + * + * Complexity: O(N) where N=depgraph.TxCount(); + */ + SetInfo<SetType> FindCandidateSet() const noexcept + { + Assume(!AllDone()); + std::optional<ClusterIndex> best; + for (auto i : m_todo) { + if (best.has_value()) { + Assume(!m_ancestor_set_feerates[i].IsEmpty()); + if (!(m_ancestor_set_feerates[i] > m_ancestor_set_feerates[*best])) continue; + } + best = i; + } + Assume(best.has_value()); + return {m_depgraph.Ancestors(*best) & m_todo, m_ancestor_set_feerates[*best]}; + } +}; + +/** Class encapsulating the state needed to perform search for good candidate sets. + * + * It is initialized for an entire DepGraph, and parts of the graph can be dropped by calling + * MarkDone(). + * + * As long as any part of the graph remains, FindCandidateSet() can be called to perform a search + * over the set of topologically-valid subsets of that remainder, with a limit on how many + * combinations are tried. + */ +template<typename SetType> +class SearchCandidateFinder +{ + /** Internal RNG. */ + InsecureRandomContext m_rng; + /** Internal dependency graph for the cluster. */ + const DepGraph<SetType>& m_depgraph; + /** Which transactions are left to do (sorted indices). */ + SetType m_todo; + +public: + /** Construct a candidate finder for a graph. + * + * @param[in] depgraph Dependency graph for the to-be-linearized cluster. + * @param[in] rng_seed A random seed to control the search order. + * + * Complexity: O(1). + */ + SearchCandidateFinder(const DepGraph<SetType>& depgraph LIFETIMEBOUND, uint64_t rng_seed) noexcept : + m_rng(rng_seed), + m_depgraph(depgraph), + m_todo(SetType::Fill(depgraph.TxCount())) {} + + /** Check whether any unlinearized transactions remain. */ + bool AllDone() const noexcept + { + return m_todo.None(); + } + + /** Find a high-feerate topologically-valid subset of what remains of the cluster. + * Requires !AllDone(). + * + * @param[in] max_iterations The maximum number of optimization steps that will be performed. + * @param[in] best A set/feerate pair with an already-known good candidate. This may + * be empty. + * @return A pair of: + * - The best (highest feerate, smallest size as tiebreaker) + * topologically valid subset (and its feerate) that was + * encountered during search. It will be at least as good as the + * best passed in (if not empty). + * - The number of optimization steps that were performed. This will + * be <= max_iterations. If strictly < max_iterations, the + * returned subset is optimal. + * + * Complexity: O(N * min(max_iterations, 2^N)) where N=depgraph.TxCount(). + */ + std::pair<SetInfo<SetType>, uint64_t> FindCandidateSet(uint64_t max_iterations, SetInfo<SetType> best) noexcept + { + Assume(!AllDone()); + + /** Type for work queue items. */ + struct WorkItem + { + /** Set of transactions definitely included (and its feerate). This must be a subset + * of m_todo, and be topologically valid (includes all in-m_todo ancestors of + * itself). */ + SetInfo<SetType> inc; + /** Set of undecided transactions. This must be a subset of m_todo, and have no overlap + * with inc. The set (inc | und) must be topologically valid. */ + SetType und; + + /** Construct a new work item. */ + WorkItem(SetInfo<SetType>&& i, SetType&& u) noexcept : + inc(std::move(i)), und(std::move(u)) {} + + /** Swap two WorkItems. */ + void Swap(WorkItem& other) noexcept + { + swap(inc, other.inc); + swap(und, other.und); + } + }; + + /** The queue of work items. */ + VecDeque<WorkItem> queue; + queue.reserve(std::max<size_t>(256, 2 * m_todo.Count())); + + // Create an initial entry with m_todo as undecided. Also use it as best if not provided, + // so that during the work processing loop below, and during the add_fn/split_fn calls, we + // do not need to deal with the best=empty case. + if (best.feerate.IsEmpty()) best = SetInfo(m_depgraph, m_todo); + queue.emplace_back(SetInfo<SetType>{}, SetType{m_todo}); + + /** Local copy of the iteration limit. */ + uint64_t iterations_left = max_iterations; + + /** Internal function to add an item to the queue of elements to explore if there are any + * transactions left to split on, and to update best. + * + * - inc: the "inc" value for the new work item (must be topological). + * - und: the "und" value for the new work item ((inc | und) must be topological). + */ + auto add_fn = [&](SetInfo<SetType> inc, SetType und) noexcept { + if (!inc.feerate.IsEmpty()) { + // If inc's feerate is better than best's, remember it as our new best. + if (inc.feerate > best.feerate) { + best = inc; + } + } else { + Assume(inc.transactions.None()); + } + + // Make sure there are undecided transactions left to split on. + if (und.None()) return; + + // Actually construct a new work item on the queue. Due to the switch to DFS when queue + // space runs out (see below), we know that no reallocation of the queue should ever + // occur. + Assume(queue.size() < queue.capacity()); + queue.emplace_back(std::move(inc), std::move(und)); + }; + + /** Internal process function. It takes an existing work item, and splits it in two: one + * with a particular transaction (and its ancestors) included, and one with that + * transaction (and its descendants) excluded. */ + auto split_fn = [&](WorkItem&& elem) noexcept { + // Any queue element must have undecided transactions left, otherwise there is nothing + // to explore anymore. + Assume(elem.und.Any()); + // The included and undecided set are all subsets of m_todo. + Assume(elem.inc.transactions.IsSubsetOf(m_todo) && elem.und.IsSubsetOf(m_todo)); + // Included transactions cannot be undecided. + Assume(!elem.inc.transactions.Overlaps(elem.und)); + + // Pick the first undecided transaction as the one to split on. + const ClusterIndex split = elem.und.First(); + + // Add a work item corresponding to exclusion of the split transaction. + const auto& desc = m_depgraph.Descendants(split); + add_fn(/*inc=*/elem.inc, + /*und=*/elem.und - desc); + + // Add a work item corresponding to inclusion of the split transaction. + const auto anc = m_depgraph.Ancestors(split) & m_todo; + add_fn(/*inc=*/elem.inc.Add(m_depgraph, anc), + /*und=*/elem.und - anc); + + // Account for the performed split. + --iterations_left; + }; + + // Work processing loop. + // + // New work items are always added at the back of the queue, but items to process use a + // hybrid approach where they can be taken from the front or the back. + // + // Depth-first search (DFS) corresponds to always taking from the back of the queue. This + // is very memory-efficient (linear in the number of transactions). Breadth-first search + // (BFS) corresponds to always taking from the front, which potentially uses more memory + // (up to exponential in the transaction count), but seems to work better in practice. + // + // The approach here combines the two: use BFS (plus random swapping) until the queue grows + // too large, at which point we temporarily switch to DFS until the size shrinks again. + while (!queue.empty()) { + // Randomly swap the first two items to randomize the search order. + if (queue.size() > 1 && m_rng.randbool()) { + queue[0].Swap(queue[1]); + } + + // Processing the first queue item, and then using DFS for everything it gives rise to, + // may increase the queue size by the number of undecided elements in there, minus 1 + // for the first queue item being removed. Thus, only when that pushes the queue over + // its capacity can we not process from the front (BFS), and should we use DFS. + while (queue.size() - 1 + queue.front().und.Count() > queue.capacity()) { + if (!iterations_left) break; + auto elem = queue.back(); + queue.pop_back(); + split_fn(std::move(elem)); + } + + // Process one entry from the front of the queue (BFS exploration) + if (!iterations_left) break; + auto elem = queue.front(); + queue.pop_front(); + split_fn(std::move(elem)); + } + + // Return the found best set and the number of iterations performed. + return {std::move(best), max_iterations - iterations_left}; + } + + /** Remove a subset of transactions from the cluster being linearized. + * + * Complexity: O(N) where N=done.Count(). + */ + void MarkDone(const SetType& done) noexcept + { + Assume(done.Any()); + Assume(done.IsSubsetOf(m_todo)); + m_todo -= done; + } +}; + +/** Find or improve a linearization for a cluster. + * + * @param[in] depgraph Dependency graph of the cluster to be linearized. + * @param[in] max_iterations Upper bound on the number of optimization steps that will be done. + * @param[in] rng_seed A random number seed to control search order. This prevents peers + * from predicting exactly which clusters would be hard for us to + * linearize. + * @param[in] old_linearization An existing linearization for the cluster (which must be + * topologically valid), or empty. + * @return A pair of: + * - The resulting linearization. It is guaranteed to be at least as + * good (in the feerate diagram sense) as old_linearization. + * - A boolean indicating whether the result is guaranteed to be + * optimal. + * + * Complexity: O(N * min(max_iterations + N, 2^N)) where N=depgraph.TxCount(). + */ +template<typename SetType> +std::pair<std::vector<ClusterIndex>, bool> Linearize(const DepGraph<SetType>& depgraph, uint64_t max_iterations, uint64_t rng_seed, Span<const ClusterIndex> old_linearization = {}) noexcept +{ + Assume(old_linearization.empty() || old_linearization.size() == depgraph.TxCount()); + if (depgraph.TxCount() == 0) return {{}, true}; + + uint64_t iterations_left = max_iterations; + std::vector<ClusterIndex> linearization; + + AncestorCandidateFinder anc_finder(depgraph); + SearchCandidateFinder src_finder(depgraph, rng_seed); + linearization.reserve(depgraph.TxCount()); + bool optimal = true; + + /** Chunking of what remains of the old linearization. */ + LinearizationChunking old_chunking(depgraph, old_linearization); + + while (true) { + // Find the highest-feerate prefix of the remainder of old_linearization. + SetInfo<SetType> best_prefix; + if (old_chunking.NumChunksLeft()) best_prefix = old_chunking.GetChunk(0); + + // Then initialize best to be either the best remaining ancestor set, or the first chunk. + auto best = anc_finder.FindCandidateSet(); + if (!best_prefix.feerate.IsEmpty() && best_prefix.feerate >= best.feerate) best = best_prefix; + + // Invoke bounded search to update best, with up to half of our remaining iterations as + // limit. + uint64_t max_iterations_now = (iterations_left + 1) / 2; + uint64_t iterations_done_now = 0; + std::tie(best, iterations_done_now) = src_finder.FindCandidateSet(max_iterations_now, best); + iterations_left -= iterations_done_now; + + if (iterations_done_now == max_iterations_now) { + optimal = false; + // If the search result is not (guaranteed to be) optimal, run intersections to make + // sure we don't pick something that makes us unable to reach further diagram points + // of the old linearization. + if (old_chunking.NumChunksLeft() > 0) { + best = old_chunking.IntersectPrefixes(best); + } + } + + // Add to output in topological order. + depgraph.AppendTopo(linearization, best.transactions); + + // Update state to reflect best is no longer to be linearized. + anc_finder.MarkDone(best.transactions); + if (anc_finder.AllDone()) break; + src_finder.MarkDone(best.transactions); + if (old_chunking.NumChunksLeft() > 0) { + old_chunking.MarkDone(best.transactions); + } + } + + return {std::move(linearization), optimal}; +} + +/** Improve a given linearization. + * + * @param[in] depgraph Dependency graph of the cluster being linearized. + * @param[in,out] linearization On input, an existing linearization for depgraph. On output, a + * potentially better linearization for the same graph. + * + * Postlinearization guarantees: + * - The resulting chunks are connected. + * - If the input has a tree shape (either all transactions have at most one child, or all + * transactions have at most one parent), the result is optimal. + * - Given a linearization L1 and a leaf transaction T in it. Let L2 be L1 with T moved to the end, + * optionally with its fee increased. Let L3 be the postlinearization of L2. L3 will be at least + * as good as L1. This means that replacing transactions with same-size higher-fee transactions + * will not worsen linearizations through a "drop conflicts, append new transactions, + * postlinearize" process. + */ +template<typename SetType> +void PostLinearize(const DepGraph<SetType>& depgraph, Span<ClusterIndex> linearization) +{ + // This algorithm performs a number of passes (currently 2); the even ones operate from back to + // front, the odd ones from front to back. Each results in an equal-or-better linearization + // than the one started from. + // - One pass in either direction guarantees that the resulting chunks are connected. + // - Each direction corresponds to one shape of tree being linearized optimally (forward passes + // guarantee this for graphs where each transaction has at most one child; backward passes + // guarantee this for graphs where each transaction has at most one parent). + // - Starting with a backward pass guarantees the moved-tree property. + // + // During an odd (forward) pass, the high-level operation is: + // - Start with an empty list of groups L=[]. + // - For every transaction i in the old linearization, from front to back: + // - Append a new group C=[i], containing just i, to the back of L. + // - While L has at least one group before C, and the group immediately before C has feerate + // lower than C: + // - If C depends on P: + // - Merge P into C, making C the concatenation of P+C, continuing with the combined C. + // - Otherwise: + // - Swap P with C, continuing with the now-moved C. + // - The output linearization is the concatenation of the groups in L. + // + // During even (backward) passes, i iterates from the back to the front of the existing + // linearization, and new groups are prepended instead of appended to the list L. To enable + // more code reuse, both passes append groups, but during even passes the meanings of + // parent/child, and of high/low feerate are reversed, and the final concatenation is reversed + // on output. + // + // In the implementation below, the groups are represented by singly-linked lists (pointing + // from the back to the front), which are themselves organized in a singly-linked circular + // list (each group pointing to its predecessor, with a special sentinel group at the front + // that points back to the last group). + // + // Information about transaction t is stored in entries[t + 1], while the sentinel is in + // entries[0]. + + /** Index of the sentinel in the entries array below. */ + static constexpr ClusterIndex SENTINEL{0}; + /** Indicator that a group has no previous transaction. */ + static constexpr ClusterIndex NO_PREV_TX{0}; + + + /** Data structure per transaction entry. */ + struct TxEntry + { + /** The index of the previous transaction in this group; NO_PREV_TX if this is the first + * entry of a group. */ + ClusterIndex prev_tx; + + // The fields below are only used for transactions that are the last one in a group + // (referred to as tail transactions below). + + /** Index of the first transaction in this group, possibly itself. */ + ClusterIndex first_tx; + /** Index of the last transaction in the previous group. The first group (the sentinel) + * points back to the last group here, making it a singly-linked circular list. */ + ClusterIndex prev_group; + /** All transactions in the group. Empty for the sentinel. */ + SetType group; + /** All dependencies of the group (descendants in even passes; ancestors in odd ones). */ + SetType deps; + /** The combined fee/size of transactions in the group. Fee is negated in even passes. */ + FeeFrac feerate; + }; + + // As an example, consider the state corresponding to the linearization [1,0,3,2], with + // groups [1,0,3] and [2], in an odd pass. The linked lists would be: + // + // +-----+ + // 0<-P-- | 0 S | ---\ Legend: + // +-----+ | + // ^ | - digit in box: entries index + // /--------------F---------+ G | (note: one more than tx value) + // v \ | | - S: sentinel group + // +-----+ +-----+ +-----+ | (empty feerate) + // 0<-P-- | 2 | <--P-- | 1 | <--P-- | 4 T | | - T: tail transaction, contains + // +-----+ +-----+ +-----+ | fields beyond prev_tv. + // ^ | - P: prev_tx reference + // G G - F: first_tx reference + // | | - G: prev_group reference + // +-----+ | + // 0<-P-- | 3 T | <--/ + // +-----+ + // ^ | + // \-F-/ + // + // During an even pass, the diagram above would correspond to linearization [2,3,0,1], with + // groups [2] and [3,0,1]. + + std::vector<TxEntry> entries(linearization.size() + 1); + + // Perform two passes over the linearization. + for (int pass = 0; pass < 2; ++pass) { + int rev = !(pass & 1); + // Construct a sentinel group, identifying the start of the list. + entries[SENTINEL].prev_group = SENTINEL; + Assume(entries[SENTINEL].feerate.IsEmpty()); + + // Iterate over all elements in the existing linearization. + for (ClusterIndex i = 0; i < linearization.size(); ++i) { + // Even passes are from back to front; odd passes from front to back. + ClusterIndex idx = linearization[rev ? linearization.size() - 1 - i : i]; + // Construct a new group containing just idx. In even passes, the meaning of + // parent/child and high/low feerate are swapped. + ClusterIndex cur_group = idx + 1; + entries[cur_group].group = SetType::Singleton(idx); + entries[cur_group].deps = rev ? depgraph.Descendants(idx): depgraph.Ancestors(idx); + entries[cur_group].feerate = depgraph.FeeRate(idx); + if (rev) entries[cur_group].feerate.fee = -entries[cur_group].feerate.fee; + entries[cur_group].prev_tx = NO_PREV_TX; // No previous transaction in group. + entries[cur_group].first_tx = cur_group; // Transaction itself is first of group. + // Insert the new group at the back of the groups linked list. + entries[cur_group].prev_group = entries[SENTINEL].prev_group; + entries[SENTINEL].prev_group = cur_group; + + // Start merge/swap cycle. + ClusterIndex next_group = SENTINEL; // We inserted at the end, so next group is sentinel. + ClusterIndex prev_group = entries[cur_group].prev_group; + // Continue as long as the current group has higher feerate than the previous one. + while (entries[cur_group].feerate >> entries[prev_group].feerate) { + // prev_group/cur_group/next_group refer to (the last transactions of) 3 + // consecutive entries in groups list. + Assume(cur_group == entries[next_group].prev_group); + Assume(prev_group == entries[cur_group].prev_group); + // The sentinel has empty feerate, which is neither higher or lower than other + // feerates. Thus, the while loop we are in here guarantees that cur_group and + // prev_group are not the sentinel. + Assume(cur_group != SENTINEL); + Assume(prev_group != SENTINEL); + if (entries[cur_group].deps.Overlaps(entries[prev_group].group)) { + // There is a dependency between cur_group and prev_group; merge prev_group + // into cur_group. The group/deps/feerate fields of prev_group remain unchanged + // but become unused. + entries[cur_group].group |= entries[prev_group].group; + entries[cur_group].deps |= entries[prev_group].deps; + entries[cur_group].feerate += entries[prev_group].feerate; + // Make the first of the current group point to the tail of the previous group. + entries[entries[cur_group].first_tx].prev_tx = prev_group; + // The first of the previous group becomes the first of the newly-merged group. + entries[cur_group].first_tx = entries[prev_group].first_tx; + // The previous group becomes whatever group was before the former one. + prev_group = entries[prev_group].prev_group; + entries[cur_group].prev_group = prev_group; + } else { + // There is no dependency between cur_group and prev_group; swap them. + ClusterIndex preprev_group = entries[prev_group].prev_group; + // If PP, P, C, N were the old preprev, prev, cur, next groups, then the new + // layout becomes [PP, C, P, N]. Update prev_groups to reflect that order. + entries[next_group].prev_group = prev_group; + entries[prev_group].prev_group = cur_group; + entries[cur_group].prev_group = preprev_group; + // The current group remains the same, but the groups before/after it have + // changed. + next_group = prev_group; + prev_group = preprev_group; + } + } + } + + // Convert the entries back to linearization (overwriting the existing one). + ClusterIndex cur_group = entries[0].prev_group; + ClusterIndex done = 0; + while (cur_group != SENTINEL) { + ClusterIndex cur_tx = cur_group; + // Traverse the transactions of cur_group (from back to front), and write them in the + // same order during odd passes, and reversed (front to back) in even passes. + if (rev) { + do { + *(linearization.begin() + (done++)) = cur_tx - 1; + cur_tx = entries[cur_tx].prev_tx; + } while (cur_tx != NO_PREV_TX); + } else { + do { + *(linearization.end() - (++done)) = cur_tx - 1; + cur_tx = entries[cur_tx].prev_tx; + } while (cur_tx != NO_PREV_TX); + } + cur_group = entries[cur_group].prev_group; + } + Assume(done == linearization.size()); + } +} + +/** Merge two linearizations for the same cluster into one that is as good as both. + * + * Complexity: O(N^2) where N=depgraph.TxCount(); O(N) if both inputs are identical. + */ +template<typename SetType> +std::vector<ClusterIndex> MergeLinearizations(const DepGraph<SetType>& depgraph, Span<const ClusterIndex> lin1, Span<const ClusterIndex> lin2) +{ + Assume(lin1.size() == depgraph.TxCount()); + Assume(lin2.size() == depgraph.TxCount()); + + /** Chunkings of what remains of both input linearizations. */ + LinearizationChunking chunking1(depgraph, lin1), chunking2(depgraph, lin2); + /** Output linearization. */ + std::vector<ClusterIndex> ret; + if (depgraph.TxCount() == 0) return ret; + ret.reserve(depgraph.TxCount()); + + while (true) { + // As long as we are not done, both linearizations must have chunks left. + Assume(chunking1.NumChunksLeft() > 0); + Assume(chunking2.NumChunksLeft() > 0); + // Find the set to output by taking the best remaining chunk, and then intersecting it with + // prefixes of remaining chunks of the other linearization. + SetInfo<SetType> best; + const auto& lin1_firstchunk = chunking1.GetChunk(0); + const auto& lin2_firstchunk = chunking2.GetChunk(0); + if (lin2_firstchunk.feerate >> lin1_firstchunk.feerate) { + best = chunking1.IntersectPrefixes(lin2_firstchunk); + } else { + best = chunking2.IntersectPrefixes(lin1_firstchunk); + } + // Append the result to the output and mark it as done. + depgraph.AppendTopo(ret, best.transactions); + chunking1.MarkDone(best.transactions); + if (chunking1.NumChunksLeft() == 0) break; + chunking2.MarkDone(best.transactions); + } + + Assume(ret.size() == depgraph.TxCount()); + return ret; +} + +} // namespace cluster_linearize + +#endif // BITCOIN_CLUSTER_LINEARIZE_H diff --git a/src/coins.cpp b/src/coins.cpp index a4e4d4ad32..a47ab8063e 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -12,7 +12,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, bool erase) { return false; } +bool CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { return false; } std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor() const { return nullptr; } bool CCoinsView::HaveCoin(const COutPoint &outpoint) const @@ -27,33 +27,34 @@ 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, bool erase) { return base->BatchWrite(mapCoins, hashBlock, erase); } +bool CCoinsViewBacked::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { return base->BatchWrite(cursor, hashBlock); } std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor() const { return base->Cursor(); } size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); } CCoinsViewCache::CCoinsViewCache(CCoinsView* baseIn, bool deterministic) : CCoinsViewBacked(baseIn), m_deterministic(deterministic), cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic), CCoinsMap::key_equal{}, &m_cache_coins_memory_resource) -{} +{ + m_sentinel.second.SelfRef(m_sentinel); +} size_t CCoinsViewCache::DynamicMemoryUsage() const { return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; } CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const { - CCoinsMap::iterator it = cacheCoins.find(outpoint); - if (it != cacheCoins.end()) - return it; - Coin tmp; - if (!base->GetCoin(outpoint, tmp)) - return cacheCoins.end(); - CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first; - if (ret->second.coin.IsSpent()) { - // The parent only has an empty entry for this outpoint; we can consider our - // version as fresh. - ret->second.flags = CCoinsCacheEntry::FRESH; + const auto [ret, inserted] = cacheCoins.try_emplace(outpoint); + if (inserted) { + if (!base->GetCoin(outpoint, ret->second.coin)) { + cacheCoins.erase(ret); + return cacheCoins.end(); + } + if (ret->second.coin.IsSpent()) { + // The parent only has an empty entry for this outpoint; we can consider our version as fresh. + ret->second.AddFlags(CCoinsCacheEntry::FRESH, *ret, m_sentinel); + } + cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage(); } - cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage(); return ret; } @@ -93,10 +94,10 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi // // If the coin doesn't exist in the current cache, or is spent but not // DIRTY, then it can be marked FRESH. - fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY); + fresh = !it->second.IsDirty(); } it->second.coin = std::move(coin); - it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); + it->second.AddFlags(CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0), *it, m_sentinel); cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); TRACE5(utxocache, add, outpoint.hash.data(), @@ -108,10 +109,13 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) { cachedCoinsUsage += coin.DynamicMemoryUsage(); - cacheCoins.emplace( + auto [it, inserted] = cacheCoins.emplace( std::piecewise_construct, std::forward_as_tuple(std::move(outpoint)), - std::forward_as_tuple(std::move(coin), CCoinsCacheEntry::DIRTY)); + std::forward_as_tuple(std::move(coin))); + if (inserted) { + it->second.AddFlags(CCoinsCacheEntry::DIRTY, *it, m_sentinel); + } } void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) { @@ -138,10 +142,10 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) { if (moveout) { *moveout = std::move(it->second.coin); } - if (it->second.flags & CCoinsCacheEntry::FRESH) { + if (it->second.IsFresh()) { cacheCoins.erase(it); } else { - it->second.flags |= CCoinsCacheEntry::DIRTY; + it->second.AddFlags(CCoinsCacheEntry::DIRTY, *it, m_sentinel); it->second.coin.Clear(); } return true; @@ -178,42 +182,40 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { hashBlock = hashBlockIn; } -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)) { +bool CCoinsViewCache::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlockIn) { + for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) { // Ignore non-dirty entries (optimization). - if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) { + if (!it->second.IsDirty()) { continue; } CCoinsMap::iterator itUs = cacheCoins.find(it->first); if (itUs == cacheCoins.end()) { // The parent cache does not have an entry, while the child cache does. // We can ignore it if it's both spent and FRESH in the child - if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) { + if (!(it->second.IsFresh() && it->second.coin.IsSpent())) { // Create the coin in the parent cache, move the data up // and mark it as dirty. - CCoinsCacheEntry& entry = cacheCoins[it->first]; - 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 = cacheCoins.try_emplace(it->first).first; + CCoinsCacheEntry& entry{itUs->second}; + if (cursor.WillErase(*it)) { + // Since this entry will be erased, + // we can move the coin into us instead of copying it entry.coin = std::move(it->second.coin); } else { entry.coin = it->second.coin; } cachedCoinsUsage += entry.coin.DynamicMemoryUsage(); - entry.flags = CCoinsCacheEntry::DIRTY; + entry.AddFlags(CCoinsCacheEntry::DIRTY, *itUs, m_sentinel); // We can mark it FRESH in the parent if it was FRESH in the child // Otherwise it might have just been flushed from the parent's cache // and already exist in the grandparent - if (it->second.flags & CCoinsCacheEntry::FRESH) { - entry.flags |= CCoinsCacheEntry::FRESH; + if (it->second.IsFresh()) { + entry.AddFlags(CCoinsCacheEntry::FRESH, *itUs, m_sentinel); } } } else { // Found the entry in the parent cache - if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) { + if (it->second.IsFresh() && !itUs->second.coin.IsSpent()) { // The coin was marked FRESH in the child cache, but the coin // exists in the parent cache. If this ever happens, it means // the FRESH flag was misapplied and there is a logic error in @@ -221,7 +223,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache"); } - if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) { + if (itUs->second.IsFresh() && it->second.coin.IsSpent()) { // The grandparent cache does not have an entry, and the coin // has been spent. We can just delete it from the parent cache. cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage(); @@ -229,16 +231,15 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn } else { // A normal modification. cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage(); - 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. + if (cursor.WillErase(*it)) { + // Since this entry will be erased, + // we can move the coin into us instead of copying it 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; + itUs->second.AddFlags(CCoinsCacheEntry::DIRTY, *itUs, m_sentinel); // NOTE: It isn't safe to mark the coin as FRESH in the parent // cache. If it already existed and was spent in the parent // cache then marking it FRESH would prevent that spentness @@ -251,12 +252,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn } bool CCoinsViewCache::Flush() { - bool fOk = base->BatchWrite(cacheCoins, hashBlock, /*erase=*/true); + auto cursor{CoinsViewCacheCursor(cachedCoinsUsage, m_sentinel, cacheCoins, /*will_erase=*/true)}; + bool fOk = base->BatchWrite(cursor, hashBlock); if (fOk) { - if (!cacheCoins.empty()) { - /* BatchWrite must erase all cacheCoins elements when erase=true. */ - throw std::logic_error("Not all cached coins were erased"); - } + cacheCoins.clear(); ReallocateCache(); } cachedCoinsUsage = 0; @@ -265,16 +264,12 @@ bool CCoinsViewCache::Flush() { 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; + auto cursor{CoinsViewCacheCursor(cachedCoinsUsage, m_sentinel, cacheCoins, /*will_erase=*/false)}; + bool fOk = base->BatchWrite(cursor, hashBlock); + if (fOk) { + if (m_sentinel.second.Next() != &m_sentinel) { + /* BatchWrite must clear flags of all entries */ + throw std::logic_error("Not all unspent flagged entries were cleared"); } } return fOk; @@ -283,7 +278,7 @@ bool CCoinsViewCache::Sync() void CCoinsViewCache::Uncache(const COutPoint& hash) { CCoinsMap::iterator it = cacheCoins.find(hash); - if (it != cacheCoins.end() && it->second.flags == 0) { + if (it != cacheCoins.end() && !it->second.IsDirty() && !it->second.IsFresh()) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); TRACE5(utxocache, uncache, hash.hash.data(), @@ -324,17 +319,33 @@ void CCoinsViewCache::ReallocateCache() void CCoinsViewCache::SanityCheck() const { size_t recomputed_usage = 0; + size_t count_flagged = 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.IsDirty()) attr |= 1; + if (entry.IsFresh()) 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(); + + // Count the number of entries we expect in the linked list. + if (entry.IsDirty() || entry.IsFresh()) ++count_flagged; + } + // Iterate over the linked list of flagged entries. + size_t count_linked = 0; + for (auto it = m_sentinel.second.Next(); it != &m_sentinel; it = it->second.Next()) { + // Verify linked list integrity. + assert(it->second.Next()->second.Prev() == it); + assert(it->second.Prev()->second.Next() == it); + // Verify they are actually flagged. + assert(it->second.IsDirty() || it->second.IsFresh()); + // Count the number of entries actually in the list. + ++count_linked; } + assert(count_linked == count_flagged); assert(recomputed_usage == cachedCoinsUsage); } diff --git a/src/coins.h b/src/coins.h index c798cc38ba..78b8eddacd 100644 --- a/src/coins.h +++ b/src/coins.h @@ -13,6 +13,7 @@ #include <serialize.h> #include <support/allocators/pool.h> #include <uint256.h> +#include <util/check.h> #include <util/hasher.h> #include <assert.h> @@ -86,6 +87,9 @@ public: } }; +struct CCoinsCacheEntry; +using CoinsCachePair = std::pair<const COutPoint, CCoinsCacheEntry>; + /** * A Coin in one level of the coins database caching hierarchy. * @@ -103,8 +107,29 @@ public: */ struct CCoinsCacheEntry { +private: + /** + * These are used to create a doubly linked list of flagged entries. + * They are set in AddFlags and unset in ClearFlags. + * A flagged entry is any entry that is either DIRTY, FRESH, or both. + * + * DIRTY entries are tracked so that only modified entries can be passed to + * the parent cache for batch writing. This is a performance optimization + * compared to giving all entries in the cache to the parent and having the + * parent scan for only modified entries. + * + * FRESH-but-not-DIRTY coins can not occur in practice, since that would + * mean a spent coin exists in the parent CCoinsView and not in the child + * CCoinsViewCache. Nevertheless, if a spent coin is retrieved from the + * parent cache, the FRESH-but-not-DIRTY coin will be tracked by the linked + * list and deleted when Sync or Flush is called on the CCoinsViewCache. + */ + CoinsCachePair* m_prev{nullptr}; + CoinsCachePair* m_next{nullptr}; + uint8_t m_flags{0}; + +public: Coin coin; // The actual cached data. - unsigned char flags; enum Flags { /** @@ -127,9 +152,59 @@ struct CCoinsCacheEntry FRESH = (1 << 1), }; - CCoinsCacheEntry() : flags(0) {} - explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {} - CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {} + CCoinsCacheEntry() noexcept = default; + explicit CCoinsCacheEntry(Coin&& coin_) noexcept : coin(std::move(coin_)) {} + ~CCoinsCacheEntry() + { + ClearFlags(); + } + + //! Adding a flag also requires a self reference to the pair that contains + //! this entry in the CCoinsCache map and a reference to the sentinel of the + //! flagged pair linked list. + inline void AddFlags(uint8_t flags, CoinsCachePair& self, CoinsCachePair& sentinel) noexcept + { + Assume(&self.second == this); + if (!m_flags && flags) { + m_prev = sentinel.second.m_prev; + m_next = &sentinel; + sentinel.second.m_prev = &self; + m_prev->second.m_next = &self; + } + m_flags |= flags; + } + inline void ClearFlags() noexcept + { + if (!m_flags) return; + m_next->second.m_prev = m_prev; + m_prev->second.m_next = m_next; + m_flags = 0; + } + inline uint8_t GetFlags() const noexcept { return m_flags; } + inline bool IsDirty() const noexcept { return m_flags & DIRTY; } + inline bool IsFresh() const noexcept { return m_flags & FRESH; } + + //! Only call Next when this entry is DIRTY, FRESH, or both + inline CoinsCachePair* Next() const noexcept { + Assume(m_flags); + return m_next; + } + + //! Only call Prev when this entry is DIRTY, FRESH, or both + inline CoinsCachePair* Prev() const noexcept { + Assume(m_flags); + return m_prev; + } + + //! Only use this for initializing the linked list sentinel + inline void SelfRef(CoinsCachePair& self) noexcept + { + Assume(&self.second == this); + m_prev = &self; + m_next = &self; + // Set sentinel to DIRTY so we can call Next on it + m_flags = DIRTY; + } }; /** @@ -144,8 +219,8 @@ using CCoinsMap = std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher, std::equal_to<COutPoint>, - PoolAllocator<std::pair<const COutPoint, CCoinsCacheEntry>, - sizeof(std::pair<const COutPoint, CCoinsCacheEntry>) + sizeof(void*) * 4>>; + PoolAllocator<CoinsCachePair, + sizeof(CoinsCachePair) + sizeof(void*) * 4>>; using CCoinsMapMemoryResource = CCoinsMap::allocator_type::ResourceType; @@ -154,7 +229,7 @@ class CCoinsViewCursor { public: CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {} - virtual ~CCoinsViewCursor() {} + virtual ~CCoinsViewCursor() = default; virtual bool GetKey(COutPoint &key) const = 0; virtual bool GetValue(Coin &coin) const = 0; @@ -168,6 +243,62 @@ private: uint256 hashBlock; }; +/** + * Cursor for iterating over the linked list of flagged entries in CCoinsViewCache. + * + * This is a helper struct to encapsulate the diverging logic between a non-erasing + * CCoinsViewCache::Sync and an erasing CCoinsViewCache::Flush. This allows the receiver + * of CCoinsView::BatchWrite to iterate through the flagged entries without knowing + * the caller's intent. + * + * However, the receiver can still call CoinsViewCacheCursor::WillErase to see if the + * caller will erase the entry after BatchWrite returns. If so, the receiver can + * perform optimizations such as moving the coin out of the CCoinsCachEntry instead + * of copying it. + */ +struct CoinsViewCacheCursor +{ + //! If will_erase is not set, iterating through the cursor will erase spent coins from the map, + //! and other coins will be unflagged (removing them from the linked list). + //! If will_erase is set, the underlying map and linked list will not be modified, + //! as the caller is expected to wipe the entire map anyway. + //! This is an optimization compared to erasing all entries as the cursor iterates them when will_erase is set. + //! Calling CCoinsMap::clear() afterwards is faster because a CoinsCachePair cannot be coerced back into a + //! CCoinsMap::iterator to be erased, and must therefore be looked up again by key in the CCoinsMap before being erased. + CoinsViewCacheCursor(size_t& usage LIFETIMEBOUND, + CoinsCachePair& sentinel LIFETIMEBOUND, + CCoinsMap& map LIFETIMEBOUND, + bool will_erase) noexcept + : m_usage(usage), m_sentinel(sentinel), m_map(map), m_will_erase(will_erase) {} + + inline CoinsCachePair* Begin() const noexcept { return m_sentinel.second.Next(); } + inline CoinsCachePair* End() const noexcept { return &m_sentinel; } + + //! Return the next entry after current, possibly erasing current + inline CoinsCachePair* NextAndMaybeErase(CoinsCachePair& current) noexcept + { + const auto next_entry{current.second.Next()}; + // If we are not going to erase the cache, we must still erase spent entries. + // Otherwise clear the flags on the entry. + if (!m_will_erase) { + if (current.second.coin.IsSpent()) { + m_usage -= current.second.coin.DynamicMemoryUsage(); + m_map.erase(current.first); + } else { + current.second.ClearFlags(); + } + } + return next_entry; + } + + inline bool WillErase(CoinsCachePair& current) const noexcept { return m_will_erase || current.second.coin.IsSpent(); } +private: + size_t& m_usage; + CoinsCachePair& m_sentinel; + CCoinsMap& m_map; + bool m_will_erase; +}; + /** Abstract view on the open txout dataset. */ class CCoinsView { @@ -191,14 +322,14 @@ public: virtual std::vector<uint256> GetHeadBlocks() const; //! Do a bulk modification (multiple Coin changes + BestBlock change). - //! The passed mapCoins can be modified. - virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true); + //! The passed cursor is used to iterate through the coins. + virtual bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock); //! Get a cursor to iterate over the whole state virtual std::unique_ptr<CCoinsViewCursor> Cursor() const; //! As we use CCoinsViews polymorphically, have a virtual destructor - virtual ~CCoinsView() {} + virtual ~CCoinsView() = default; //! Estimate database size (0 if not implemented) virtual size_t EstimateSize() const { return 0; } @@ -218,7 +349,7 @@ public: uint256 GetBestBlock() const override; std::vector<uint256> GetHeadBlocks() const override; void SetBackend(CCoinsView &viewIn); - bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true) override; + bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override; std::unique_ptr<CCoinsViewCursor> Cursor() const override; size_t EstimateSize() const override; }; @@ -237,6 +368,8 @@ protected: */ mutable uint256 hashBlock; mutable CCoinsMapMemoryResource m_cache_coins_memory_resource{}; + /* The starting sentinel of the flagged entry circular doubly linked list. */ + mutable CoinsCachePair m_sentinel; mutable CCoinsMap cacheCoins; /* Cached dynamic memory usage for the inner Coin objects. */ @@ -255,7 +388,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, bool erase = true) override; + bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override; std::unique_ptr<CCoinsViewCursor> Cursor() const override { throw std::logic_error("CCoinsViewCache cursor iteration not supported."); } diff --git a/src/common/args.cpp b/src/common/args.cpp index caff36fdb3..a37a16b62b 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -159,6 +159,7 @@ std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const ChainTypeToString(ChainType::REGTEST), ChainTypeToString(ChainType::SIGNET), ChainTypeToString(ChainType::TESTNET), + ChainTypeToString(ChainType::TESTNET4), ChainTypeToString(ChainType::MAIN), }; @@ -773,10 +774,11 @@ std::variant<ChainType, std::string> ArgsManager::GetChainArg() const const bool fRegTest = get_net("-regtest"); const bool fSigNet = get_net("-signet"); const bool fTestNet = get_net("-testnet"); + const bool fTestNet4 = get_net("-testnet4"); const auto chain_arg = GetArg("-chain"); - if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) { - throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one."); + if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet + (int)fTestNet4 > 1) { + throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet, -testnet4 and -chain. Can use at most one."); } if (chain_arg) { if (auto parsed = ChainTypeFromString(*chain_arg)) return *parsed; @@ -786,6 +788,7 @@ std::variant<ChainType, std::string> ArgsManager::GetChainArg() const if (fRegTest) return ChainType::REGTEST; if (fSigNet) return ChainType::SIGNET; if (fTestNet) return ChainType::TESTNET; + if (fTestNet4) return ChainType::TESTNET4; return ChainType::MAIN; } diff --git a/src/common/args.h b/src/common/args.h index 78a61313b9..323a86d8dc 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -423,7 +423,7 @@ private: fs::path GetDataDir(bool net_specific) const; /** - * Return -regtest/-signet/-testnet/-chain= setting as a ChainType enum if a + * Return -regtest/-signet/-testnet/-testnet4/-chain= setting as a ChainType enum if a * recognized chain type was set, or as a string if an unrecognized chain * name was set. Raise an exception if an invalid combination of flags was * provided. diff --git a/src/common/bloom.cpp b/src/common/bloom.cpp index ca6af90b76..076ee40635 100644 --- a/src/common/bloom.cpp +++ b/src/common/bloom.cpp @@ -239,7 +239,7 @@ bool CRollingBloomFilter::contains(Span<const unsigned char> vKey) const void CRollingBloomFilter::reset() { - nTweak = GetRand<unsigned int>(); + nTweak = FastRandomContext().rand<unsigned int>(); nEntriesThisGeneration = 0; nGeneration = 1; std::fill(data.begin(), data.end(), 0); diff --git a/src/common/messages.cpp b/src/common/messages.cpp index 9e88ca8b0f..5fe3e9e4d8 100644 --- a/src/common/messages.cpp +++ b/src/common/messages.cpp @@ -53,6 +53,34 @@ const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap() return FEE_MODES; } +std::string FeeModeInfo(const std::pair<std::string, FeeEstimateMode>& mode, std::string& default_info) +{ + switch (mode.second) { + case FeeEstimateMode::UNSET: + return strprintf("%s means no mode set (%s). \n", mode.first, default_info); + case FeeEstimateMode::ECONOMICAL: + return strprintf("%s estimates use a shorter time horizon, making them more\n" + "responsive to short-term drops in the prevailing fee market. This mode\n" + "potentially returns a lower fee rate estimate.\n", mode.first); + case FeeEstimateMode::CONSERVATIVE: + return strprintf("%s estimates use a longer time horizon, making them\n" + "less responsive to short-term drops in the prevailing fee market. This mode\n" + "potentially returns a higher fee rate estimate.\n", mode.first); + default: + // Other modes apart from the ones handled are fee rate units; they should not be clarified. + assert(false); + } +} + +std::string FeeModesDetail(std::string default_info) +{ + std::string info; + for (const auto& fee_mode : FeeModeMap()) { + info += FeeModeInfo(fee_mode, default_info); + } + return strprintf("%s \n%s", FeeModes(", "), info); +} + std::string FeeModes(const std::string& delimiter) { return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; }); @@ -100,8 +128,8 @@ bilingual_str TransactionErrorString(const TransactionError err) return Untranslated("No error"); case TransactionError::MISSING_INPUTS: return Untranslated("Inputs missing or spent"); - case TransactionError::ALREADY_IN_CHAIN: - return Untranslated("Transaction already in block chain"); + case TransactionError::ALREADY_IN_UTXO_SET: + return Untranslated("Transaction outputs already in utxo set"); case TransactionError::MEMPOOL_REJECTED: return Untranslated("Transaction rejected by mempool"); case TransactionError::MEMPOOL_ERROR: diff --git a/src/common/messages.h b/src/common/messages.h index 68e7bb2169..5827fccee0 100644 --- a/src/common/messages.h +++ b/src/common/messages.h @@ -26,6 +26,8 @@ enum class PSBTError; bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode); std::string StringForFeeReason(FeeReason reason); std::string FeeModes(const std::string& delimiter); +std::string FeeModeInfo(std::pair<std::string, FeeEstimateMode>& mode); +std::string FeeModesDetail(std::string default_info); std::string InvalidEstimateModeErrorMessage(); bilingual_str PSBTErrorString(PSBTError error); bilingual_str TransactionErrorString(const node::TransactionError error); diff --git a/src/consensus/params.h b/src/consensus/params.h index 25f53eb620..d970e41637 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -108,6 +108,7 @@ struct Params { /** Proof of work parameters */ uint256 powLimit; bool fPowAllowMinDifficultyBlocks; + bool enforce_BIP94; bool fPowNoRetargeting; int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; diff --git a/src/core_io.h b/src/core_io.h index 4405f5c8f8..9305bb7239 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -37,15 +37,6 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco [[nodiscard]] bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); -/** - * Parse a hex string into 256 bits - * @param[in] strHex a hex-formatted, 64-character string - * @param[out] result the result of the parsing - * @returns true if successful, false if not - * - * @see ParseHashV for an RPC-oriented version of this - */ -bool ParseHashStr(const std::string& strHex, uint256& result); [[nodiscard]] util::Result<int> SighashFromStr(const std::string& sighash); // core_write.cpp diff --git a/src/core_read.cpp b/src/core_read.cpp index 114f92fc45..23f341c230 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -234,18 +234,9 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk) return true; } -bool ParseHashStr(const std::string& strHex, uint256& result) -{ - if ((strHex.size() != 64) || !IsHex(strHex)) - return false; - - result.SetHex(strHex); - return true; -} - util::Result<int> SighashFromStr(const std::string& sighash) { - static std::map<std::string, int> map_sighash_values = { + static const std::map<std::string, int> map_sighash_values = { {std::string("DEFAULT"), int(SIGHASH_DEFAULT)}, {std::string("ALL"), int(SIGHASH_ALL)}, {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)}, diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h index cb53e1743e..222b866b6d 100644 --- a/src/crypto/muhash.h +++ b/src/crypto/muhash.h @@ -97,7 +97,7 @@ private: public: /* The empty set. */ - MuHash3072() noexcept {}; + MuHash3072() noexcept = default; /* A singleton with variable sized data in it. */ explicit MuHash3072(Span<const unsigned char> in) noexcept; diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index c883bd2f03..deedc0a6d1 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -7,8 +7,9 @@ #include <crypto/sha256.h> #include <crypto/common.h> -#include <assert.h> -#include <string.h> +#include <algorithm> +#include <cassert> +#include <cstring> #if !defined(DISABLE_OPTIMIZED_SHA256) #include <compat/cpuid.h> @@ -621,7 +622,7 @@ std::string SHA256AutoDetect(sha256_implementation::UseImplementation use_implem } } -#if defined(ENABLE_X86_SHANI) +#if defined(ENABLE_SSE41) && defined(ENABLE_X86_SHANI) if (have_x86_shani) { Transform = sha256_x86_shani::Transform; TransformD64 = TransformD64Wrapper<sha256_x86_shani::Transform>; diff --git a/src/crypto/sha256_x86_shani.cpp b/src/crypto/sha256_x86_shani.cpp index 79871bfcc1..7471828193 100644 --- a/src/crypto/sha256_x86_shani.cpp +++ b/src/crypto/sha256_x86_shani.cpp @@ -6,7 +6,7 @@ // Written and placed in public domain by Jeffrey Walton. // Based on code from Intel, and by Sean Gulley for the miTLS project. -#ifdef ENABLE_X86_SHANI +#if defined(ENABLE_SSE41) && defined(ENABLE_X86_SHANI) #include <stdint.h> #include <immintrin.h> diff --git a/src/crypto/sha3.h b/src/crypto/sha3.h index e8e91f1ee4..a28c5311ff 100644 --- a/src/crypto/sha3.h +++ b/src/crypto/sha3.h @@ -32,7 +32,7 @@ private: public: static constexpr size_t OUTPUT_SIZE = 32; - SHA3_256() {} + SHA3_256() = default; SHA3_256& Write(Span<const unsigned char> data); SHA3_256& Finalize(Span<unsigned char> output); SHA3_256& Reset(); diff --git a/src/cuckoocache.h b/src/cuckoocache.h index df320ed465..8370179395 100644 --- a/src/cuckoocache.h +++ b/src/cuckoocache.h @@ -14,7 +14,6 @@ #include <cstring> #include <limits> #include <memory> -#include <optional> #include <utility> #include <vector> @@ -360,16 +359,15 @@ public: * structure * @returns A pair of the maximum number of elements storable (see setup() * documentation for more detail) and the approximate total size of these - * elements in bytes or std::nullopt if the size requested is too large. + * elements in bytes. */ - std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t bytes) + std::pair<uint32_t, size_t> setup_bytes(size_t bytes) { - size_t requested_num_elems = bytes / sizeof(Element); - if (std::numeric_limits<uint32_t>::max() < requested_num_elems) { - return std::nullopt; - } + uint32_t requested_num_elems(std::min<size_t>( + bytes / sizeof(Element), + std::numeric_limits<uint32_t>::max())); - auto num_elems = setup(bytes/sizeof(Element)); + auto num_elems = setup(requested_num_elems); size_t approx_size_bytes = num_elems * sizeof(Element); return std::make_pair(num_elems, approx_size_bytes); diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 775496e21b..479064d468 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -100,7 +100,7 @@ public: assert(p <= limit); base[std::min(bufsize - 1, (int)(p - base))] = '\0'; - LogPrintLevel(BCLog::LEVELDB, BCLog::Level::Debug, "%s", base); // NOLINT(bitcoin-unterminated-logprintf) + LogDebug(BCLog::LEVELDB, "%s\n", util::RemoveSuffixView(base, "\n")); if (base != buffer) { delete[] base; } diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 2bff663d8b..6aba0c371d 100644 --- a/src/flatfile.cpp +++ b/src/flatfile.cpp @@ -30,7 +30,7 @@ fs::path FlatFileSeq::FileName(const FlatFilePos& pos) const return m_dir / fs::u8path(strprintf("%s%05u.dat", m_prefix, pos.nFile)); } -FILE* FlatFileSeq::Open(const FlatFilePos& pos, bool read_only) +FILE* FlatFileSeq::Open(const FlatFilePos& pos, bool read_only) const { if (pos.IsNull()) { return nullptr; @@ -52,7 +52,7 @@ FILE* FlatFileSeq::Open(const FlatFilePos& pos, bool read_only) return file; } -size_t FlatFileSeq::Allocate(const FlatFilePos& pos, size_t add_size, bool& out_of_space) +size_t FlatFileSeq::Allocate(const FlatFilePos& pos, size_t add_size, bool& out_of_space) const { out_of_space = false; @@ -78,7 +78,7 @@ size_t FlatFileSeq::Allocate(const FlatFilePos& pos, size_t add_size, bool& out_ return 0; } -bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize) +bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize) const { FILE* file = Open(FlatFilePos(pos.nFile, 0)); // Avoid fseek to nPos if (!file) { diff --git a/src/flatfile.h b/src/flatfile.h index 26b466db71..3edb0b85da 100644 --- a/src/flatfile.h +++ b/src/flatfile.h @@ -18,7 +18,7 @@ struct FlatFilePos SERIALIZE_METHODS(FlatFilePos, obj) { READWRITE(VARINT_MODE(obj.nFile, VarIntMode::NONNEGATIVE_SIGNED), VARINT(obj.nPos)); } - FlatFilePos() {} + FlatFilePos() = default; FlatFilePos(int nFileIn, unsigned int nPosIn) : nFile(nFileIn), @@ -63,7 +63,7 @@ public: fs::path FileName(const FlatFilePos& pos) const; /** Open a handle to the file at the given position. */ - FILE* Open(const FlatFilePos& pos, bool read_only = false); + FILE* Open(const FlatFilePos& pos, bool read_only = false) const; /** * Allocate additional space in a file after the given starting position. The amount allocated @@ -74,7 +74,7 @@ public: * @param[out] out_of_space Whether the allocation failed due to insufficient disk space. * @return The number of bytes successfully allocated. */ - size_t Allocate(const FlatFilePos& pos, size_t add_size, bool& out_of_space); + size_t Allocate(const FlatFilePos& pos, size_t add_size, bool& out_of_space) const; /** * Commit a file to disk, and optionally truncate off extra pre-allocated bytes if final. @@ -83,7 +83,7 @@ public: * @param[in] finalize True if no more data will be written to this file. * @return true on success, false on failure. */ - bool Flush(const FlatFilePos& pos, bool finalize = false); + bool Flush(const FlatFilePos& pos, bool finalize = false) const; }; #endif // BITCOIN_FLATFILE_H diff --git a/src/headerssync.cpp b/src/headerssync.cpp index e14de004f5..b41fe07754 100644 --- a/src/headerssync.cpp +++ b/src/headerssync.cpp @@ -25,7 +25,7 @@ static_assert(sizeof(CompressedHeader) == 48); HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus_params, const CBlockIndex* chain_start, const arith_uint256& minimum_required_work) : - m_commit_offset(GetRand<unsigned>(HEADER_COMMITMENT_PERIOD)), + m_commit_offset(FastRandomContext().randrange<unsigned>(HEADER_COMMITMENT_PERIOD)), m_id(id), m_consensus_params(consensus_params), m_chain_start(chain_start), m_minimum_required_work(minimum_required_work), diff --git a/src/headerssync.h b/src/headerssync.h index e93f67e6da..5e399eb861 100644 --- a/src/headerssync.h +++ b/src/headerssync.h @@ -100,7 +100,7 @@ struct CompressedHeader { class HeadersSyncState { public: - ~HeadersSyncState() {} + ~HeadersSyncState() = default; enum class State { /** PRESYNC means the peer has not yet demonstrated their chain has diff --git a/src/httpserver.h b/src/httpserver.h index 991081bab8..33216a0119 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -131,7 +131,7 @@ public: */ void WriteReply(int nStatus, std::string_view reply = "") { - WriteReply(nStatus, std::as_bytes(std::span{reply.data(), reply.size()})); + WriteReply(nStatus, std::as_bytes(std::span{reply})); } void WriteReply(int nStatus, std::span<const std::byte> reply); }; @@ -156,7 +156,7 @@ class HTTPClosure { public: virtual void operator()() = 0; - virtual ~HTTPClosure() {} + virtual ~HTTPClosure() = default; }; /** Event class. This can be used either as a cross-thread trigger or as a timer. diff --git a/src/index/disktxpos.h b/src/index/disktxpos.h index 1004f7ae87..a03638469e 100644 --- a/src/index/disktxpos.h +++ b/src/index/disktxpos.h @@ -20,7 +20,7 @@ struct CDiskTxPos : public FlatFilePos CDiskTxPos(const FlatFilePos &blockIn, unsigned int nTxOffsetIn) : FlatFilePos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { } - CDiskTxPos() {} + CDiskTxPos() = default; }; #endif // BITCOIN_INDEX_DISKTXPOS_H diff --git a/src/init.cpp b/src/init.cpp index 9d8949f99f..faaf3353d0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -8,7 +8,6 @@ #include <init.h> #include <kernel/checks.h> -#include <kernel/validation_cache_sizes.h> #include <addrman.h> #include <banman.h> @@ -54,7 +53,6 @@ #include <node/mempool_persist_args.h> #include <node/miner.h> #include <node/peerman_args.h> -#include <node/validation_cache_args.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/fees_args.h> @@ -119,7 +117,6 @@ using common::AmountErrMsg; using common::InvalidPortErrMsg; using common::ResolveErrMsg; -using kernel::ValidationCacheSizes; using node::ApplyArgsManOptions; using node::BlockManager; @@ -299,10 +296,11 @@ void Shutdown(NodeContext& node) StopTorControl(); + if (node.chainman && node.chainman->m_thread_load.joinable()) node.chainman->m_thread_load.join(); // After everything has been shut down, but before things get flushed, stop the - // scheduler and load block thread. + // the scheduler. After this point, SyncWithValidationInterfaceQueue() should not be called anymore + // as this would prevent the shutdown from completing. if (node.scheduler) node.scheduler->stop(); - if (node.chainman && node.chainman->m_thread_load.joinable()) node.chainman->m_thread_load.join(); // After the threads that potentially access these pointers have been stopped, // destruct and reset all to nullptr. @@ -452,10 +450,12 @@ void SetupServerArgs(ArgsManager& argsman) const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN); const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET); + const auto testnet4BaseParams = CreateBaseChainParams(ChainType::TESTNET4); const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET); const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST); const auto defaultChainParams = CreateChainParams(argsman, ChainType::MAIN); const auto testnetChainParams = CreateChainParams(argsman, ChainType::TESTNET); + const auto testnet4ChainParams = CreateChainParams(argsman, ChainType::TESTNET4); const auto signetChainParams = CreateChainParams(argsman, ChainType::SIGNET); const auto regtestChainParams = CreateChainParams(argsman, ChainType::REGTEST); @@ -469,8 +469,15 @@ void SetupServerArgs(ArgsManager& argsman) #if HAVE_SYSTEM argsman.AddArg("-alertnotify=<cmd>", "Execute command when an alert is raised (%s in cmd is replaced by message)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif - argsman.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnet4ChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-blocksxor", + strprintf("Whether an XOR-key applies to blocksdir *.dat files. " + "The created XOR-key will be zeros for an existing blocksdir or when `-blocksxor=0` is " + "set, and random for a freshly initialized blocksdir. " + "(default: %u)", + kernel::DEFAULT_XOR_BLOCKSDIR), + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); #if HAVE_SYSTEM argsman.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -488,7 +495,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s, signet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), signetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); + argsman.AddArg("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnet4ChainParams->GetConsensus().nMinimumChainWork.GetHex(), signetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); argsman.AddArg("-par=<n>", strprintf("Set the number of script verification threads (0 = auto, up to %d, <0 = leave that many cores free, default: %d)", MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -517,7 +524,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), testnet4BaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -544,7 +551,7 @@ void SetupServerArgs(ArgsManager& argsman) 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); - argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); #ifdef HAVE_SOCKADDR_UN argsman.AddArg("-proxy=<ip:port|path>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled). May be a local file path prefixed with 'unix:' if the proxy supports it.", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION); #else @@ -619,7 +626,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-test=<option>", "Pass a test-only option. Options include : " + Join(TEST_OPTIONS_DOC, ", ") + ".", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); 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("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_VALIDATION_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)", Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)), @@ -640,7 +647,7 @@ void SetupServerArgs(ArgsManager& argsman) "is of this size or less (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-mempoolfullrbf", strprintf("(DEPRECATED) Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", @@ -661,7 +668,7 @@ void SetupServerArgs(ArgsManager& argsman) 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("-rpccookieperms=<readable-by>", strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC); - argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); + argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC); argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC); @@ -908,6 +915,11 @@ bool AppInitParameterInteraction(const ArgsManager& args) return InitError(errors); } + // Testnet3 deprecation warning + if (chain == ChainType::TESTNET) { + LogInfo("Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4.\n"); + } + // Warn if unrecognized section name are present in the config file. bilingual_str warnings; for (const auto& section : args.GetUnrecognizedSections()) { @@ -1154,14 +1166,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) args.GetArg("-datadir", ""), fs::PathToString(fs::current_path())); } - ValidationCacheSizes validation_cache_sizes{}; - ApplyArgsManOptions(args, validation_cache_sizes); - if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes) - || !InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes)) - { - return InitError(strprintf(_("Unable to allocate memory for -maxsigcachesize: '%s' MiB"), args.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_BYTES >> 20))); - } - assert(!node.scheduler); node.scheduler = std::make_unique<CScheduler>(); auto& scheduler = *node.scheduler; @@ -1273,11 +1277,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.addrman = std::move(*addrman); } + FastRandomContext rng; assert(!node.banman); 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>(), + node.connman = std::make_unique<CConnman>(rng.rand64(), + rng.rand64(), *node.addrman, *node.netgroupman, chainparams, args.GetBoolArg("-networkactive", true)); assert(!node.fee_estimator); @@ -1543,7 +1548,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024)); - node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts); + try { + node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts); + } catch (std::exception& e) { + return InitError(strprintf(Untranslated("Failed to initialize ChainstateManager: %s"), e.what())); + } ChainstateManager& chainman = *node.chainman; // This is defined and set here instead of inline in validation.h to avoid a hard @@ -1890,6 +1899,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) CService onion_service_target; if (!connOptions.onion_binds.empty()) { onion_service_target = connOptions.onion_binds.front(); + } else if (!connOptions.vBinds.empty()) { + onion_service_target = connOptions.vBinds.front(); } else { onion_service_target = DefaultOnionServiceTarget(); connOptions.onion_binds.push_back(onion_service_target); diff --git a/src/init.h b/src/init.h index ead5f5e0d2..40a5da3c0b 100644 --- a/src/init.h +++ b/src/init.h @@ -6,9 +6,7 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H -#include <any> -#include <memory> -#include <string> +#include <atomic> //! Default value for -daemon option static constexpr bool DEFAULT_DAEMON = false; diff --git a/src/init/common.cpp b/src/init/common.cpp index 00ef879dc1..36142c2b9a 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -27,9 +27,9 @@ void AddLoggingArgs(ArgsManager& argsman) { argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file (default: %s). Relative paths will be prefixed by a net-specific datadir location. Pass -nodebuglogfile to disable writing the log to a file.", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-debug=<category>", "Output debug and trace logging (default: -nodebug, supplying <category> is optional). " - "If <category> is not supplied or if <category> = 1, output all debug and trace logging. <category> can be: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.", + "If <category> is not supplied or if <category> is 1 or \"all\", output all debug logging. If <category> is 0 or \"none\", any other categories are ignored. Other valid values for <category> are: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging for all categories except the specified category. This option can be specified multiple times to exclude multiple categories.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging for all categories except the specified category. This option can be specified multiple times to exclude multiple categories. This takes priority over \"-debug\"", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-loglevel=<level>|<category>:<level>", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC. Possible values are %s (default=%s). The following levels are always logged: error, warning, info. If <category>:<level> is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. <category> can be: %s.", LogInstance().LogLevelsString(), LogInstance().LogLevelToStr(BCLog::DEFAULT_LOG_LEVEL), LogInstance().LogCategoriesString()), ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 9da5cb9637..af45f81f95 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -123,7 +123,7 @@ struct BlockInfo { class Chain { public: - virtual ~Chain() {} + virtual ~Chain() = default; //! Get current chain height, not including genesis block (returns 0 if //! chain only contains genesis block, nullopt if chain does not contain @@ -309,7 +309,7 @@ public: class Notifications { public: - virtual ~Notifications() {} + virtual ~Notifications() = default; virtual void transactionAddedToMempool(const CTransactionRef& tx) {} virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {} virtual void blockConnected(ChainstateRole role, const BlockInfo& block) {} @@ -371,7 +371,7 @@ public: class ChainClient { public: - virtual ~ChainClient() {} + virtual ~ChainClient() = default; //! Register rpcs. virtual void registerRpcs() = 0; diff --git a/src/interfaces/echo.h b/src/interfaces/echo.h index 5578d9d9e6..964dbb02fa 100644 --- a/src/interfaces/echo.h +++ b/src/interfaces/echo.h @@ -13,7 +13,7 @@ namespace interfaces { class Echo { public: - virtual ~Echo() {} + virtual ~Echo() = default; //! Echo provided string. virtual std::string echo(const std::string& echo) = 0; diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h index 7751d82347..6fc14ed0b4 100644 --- a/src/interfaces/handler.h +++ b/src/interfaces/handler.h @@ -22,7 +22,7 @@ namespace interfaces { class Handler { public: - virtual ~Handler() {} + virtual ~Handler() = default; //! Disconnect the handler. virtual void disconnect() = 0; diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 7d71a01450..cebe97edb7 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -5,9 +5,11 @@ #ifndef BITCOIN_INTERFACES_MINING_H #define BITCOIN_INTERFACES_MINING_H +#include <node/types.h> +#include <uint256.h> + #include <memory> #include <optional> -#include <uint256.h> namespace node { struct CBlockTemplate; @@ -26,7 +28,7 @@ namespace interfaces { class Mining { public: - virtual ~Mining() {} + virtual ~Mining() = default; //! If this chain is exclusively used for testing virtual bool isTestChain() = 0; @@ -41,10 +43,10 @@ public: * Construct a new block template * * @param[in] script_pub_key the coinbase output - * @param[in] use_mempool set false to omit mempool transactions + * @param[in] options options for creating the block * @returns a block template */ - virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0; + virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, const node::BlockCreateOptions& options={}) = 0; /** * Processes new block. A valid new block is automatically relayed to peers. diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 2bb895dd47..81844c6185 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -59,7 +59,7 @@ struct BlockAndHeaderTipInfo class ExternalSigner { public: - virtual ~ExternalSigner() {}; + virtual ~ExternalSigner() = default; //! Get signer display name virtual std::string getName() = 0; @@ -69,7 +69,7 @@ public: class Node { public: - virtual ~Node() {} + virtual ~Node() = default; //! Init logging. virtual void initLogging() = 0; @@ -162,12 +162,18 @@ public: //! Get mempool dynamic usage. virtual size_t getMempoolDynamicUsage() = 0; + //! Get mempool maximum memory usage. + virtual size_t getMempoolMaxUsage() = 0; + //! Get header tip height and time. virtual bool getHeaderTip(int& height, int64_t& block_time) = 0; //! Get num blocks. virtual int getNumBlocks() = 0; + //! Get network local addresses. + virtual std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() = 0; + //! Get best block hash. virtual uint256 getBestBlockHash() = 0; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index f7bcca58cf..df1ced48a7 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -65,7 +65,7 @@ using WalletValueMap = std::map<std::string, std::string>; class Wallet { public: - virtual ~Wallet() {} + virtual ~Wallet() = default; //! Encrypt wallet. virtual bool encryptWallet(const SecureString& wallet_passphrase) = 0; @@ -342,8 +342,11 @@ public: //! Migrate a wallet virtual util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) = 0; + //! Returns true if wallet stores encryption keys + virtual bool isEncrypted(const std::string& wallet_name) = 0; + //! Return available wallets in wallet directory. - virtual std::vector<std::string> listWalletDir() = 0; + virtual std::vector<std::pair<std::string, std::string>> listWalletDir() = 0; //! Return interfaces for accessing wallets (if any). virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h index deeba7e318..261ec3be58 100644 --- a/src/kernel/blockmanager_opts.h +++ b/src/kernel/blockmanager_opts.h @@ -14,12 +14,15 @@ class CChainParams; namespace kernel { +static constexpr bool DEFAULT_XOR_BLOCKSDIR{true}; + /** * An options struct for `BlockManager`, more ergonomically referred to as * `BlockManager::Options` due to the using-declaration in `BlockManager`. */ struct BlockManagerOpts { const CChainParams& chainparams; + bool use_xor{DEFAULT_XOR_BLOCKSDIR}; uint64_t prune_target{0}; bool fast_prune{false}; const fs::path blocks_dir; diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index bf3a340cb8..4fd2d5e2d0 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -26,6 +26,16 @@ #include <cstring> #include <type_traits> +// Workaround MSVC bug triggering C7595 when calling consteval constructors in +// initializer lists. +// A fix may be on the way: +// https://developercommunity.visualstudio.com/t/consteval-conversion-function-fails/1579014 +#if defined(_MSC_VER) +auto consteval_ctor(auto&& input) { return input; } +#else +#define consteval_ctor(input) (input) +#endif + 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; @@ -76,20 +86,21 @@ public: consensus.signet_challenge.clear(); consensus.nSubsidyHalvingInterval = 210000; consensus.script_flag_exceptions.emplace( // BIP16 exception - uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22"), SCRIPT_VERIFY_NONE); + uint256{"00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22"}, SCRIPT_VERIFY_NONE); consensus.script_flag_exceptions.emplace( // Taproot exception - uint256S("0x0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad"), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS); + uint256{"0000000000000000000f14c35b2d841e986ab5441de8c585d5ffe55ea1e395ad"}, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS); consensus.BIP34Height = 227931; - consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); + consensus.BIP34Hash = uint256{"000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"}; 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.powLimit = uint256{"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; + consensus.enforce_BIP94 = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016 consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing @@ -104,8 +115,8 @@ public: 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("0x000000000000000000000000000000000000000063c4ebd298db40af57541800"); - consensus.defaultAssumeValid = uint256S("0x000000000000000000026811d149d4d261995ec5b3f64f439a0a10e1a464af9a"); // 824000 + consensus.nMinimumChainWork = uint256{"000000000000000000000000000000000000000063c4ebd298db40af57541800"}; + consensus.defaultAssumeValid = uint256{"000000000000000000026811d149d4d261995ec5b3f64f439a0a10e1a464af9a"}; // 824000 /** * The message start string is designed to be unlikely to occur in normal data. @@ -123,8 +134,8 @@ public: genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256{"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"}); + assert(genesis.hashMerkleRoot == uint256{"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"}); // Note that of those which support the service bits prefix, most only support a subset of // possible options. @@ -157,30 +168,35 @@ public: 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")}, + { 11111, uint256{"0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"}}, + { 33333, uint256{"000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"}}, + { 74000, uint256{"0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"}}, + {105000, uint256{"00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"}}, + {134444, uint256{"00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"}}, + {168000, uint256{"000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"}}, + {193000, uint256{"000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"}}, + {210000, uint256{"000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"}}, + {216116, uint256{"00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"}}, + {225430, uint256{"00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"}}, + {250000, uint256{"000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"}}, + {279000, uint256{"0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"}}, + {295000, uint256{"00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"}}, } }; m_assumeutxo_data = { - // TODO to be specified in a future patch. + { + .height = 840'000, + .hash_serialized = AssumeutxoHash{uint256{"a2a5521b1b5ab65f67818e5e8eccabb7171a517f9e2382208f77687310768f96"}}, + .m_chain_tx_count = 991032194, + .blockhash = consteval_ctor(uint256{"0000000000000000000320283a032748cef8227873ff4872689bf23f1cda83a5"}), + } }; chainTxData = ChainTxData{ // Data from RPC: getchaintxstats 4096 000000000000000000026811d149d4d261995ec5b3f64f439a0a10e1a464af9a .nTime = 1704194835, - .nTxCount = 946728933, + .tx_count = 946728933, .dTxRate = 6.569290261471664, }; } @@ -197,18 +213,19 @@ public: consensus.signet_challenge.clear(); consensus.nSubsidyHalvingInterval = 210000; consensus.script_flag_exceptions.emplace( // BIP16 exception - uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105"), SCRIPT_VERIFY_NONE); + uint256{"00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105"}, SCRIPT_VERIFY_NONE); consensus.BIP34Height = 21111; - consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); + consensus.BIP34Hash = uint256{"0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"}; 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.powLimit = uint256{"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; + consensus.enforce_BIP94 = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing @@ -223,8 +240,8 @@ public: 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("0x000000000000000000000000000000000000000000000c59b14e264ba6c15db9"); - consensus.defaultAssumeValid = uint256S("0x000000000001323071f38f21ea5aae529ece491eadaccce506a59bcc2d968917"); // 2550000 + consensus.nMinimumChainWork = uint256{"000000000000000000000000000000000000000000000c59b14e264ba6c15db9"}; + consensus.defaultAssumeValid = uint256{"000000000001323071f38f21ea5aae529ece491eadaccce506a59bcc2d968917"}; // 2550000 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -237,8 +254,8 @@ public: genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256{"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"}); + assert(genesis.hashMerkleRoot == uint256{"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"}); vFixedSeeds.clear(); vSeeds.clear(); @@ -264,29 +281,127 @@ public: checkpointData = { { - {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")}, + {546, uint256{"000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"}}, } }; m_assumeutxo_data = { { .height = 2'500'000, - .hash_serialized = AssumeutxoHash{uint256S("0xf841584909f68e47897952345234e37fcd9128cd818f41ee6c3ca68db8071be7")}, - .nChainTx = 66484552, - .blockhash = uint256S("0x0000000000000093bcb68c03a9a168ae252572d348a2eaeba2cdf9231d73206f") + .hash_serialized = AssumeutxoHash{uint256{"f841584909f68e47897952345234e37fcd9128cd818f41ee6c3ca68db8071be7"}}, + .m_chain_tx_count = 66484552, + .blockhash = consteval_ctor(uint256{"0000000000000093bcb68c03a9a168ae252572d348a2eaeba2cdf9231d73206f"}), } }; chainTxData = ChainTxData{ // Data from RPC: getchaintxstats 4096 000000000001323071f38f21ea5aae529ece491eadaccce506a59bcc2d968917 .nTime = 1703579240, - .nTxCount = 67845391, + .tx_count = 67845391, .dTxRate = 1.464436832560951, }; } }; /** + * Testnet (v4): public test network which is reset from time to time. + */ +class CTestNet4Params : public CChainParams { +public: + CTestNet4Params() { + m_chain_type = ChainType::TESTNET4; + consensus.signet_blocks = false; + consensus.signet_challenge.clear(); + consensus.nSubsidyHalvingInterval = 210000; + consensus.BIP34Height = 1; + consensus.BIP34Hash = uint256{}; + consensus.BIP65Height = 1; + consensus.BIP66Height = 1; + consensus.CSVHeight = 1; + consensus.SegwitHeight = 1; + consensus.MinBIP9WarningHeight = 0; + consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 10 * 60; + consensus.fPowAllowMinDifficultyBlocks = true; + consensus.enforce_BIP94 = 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 = 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{"000000000000000000000000000000000000000000000056faca98a0cd9bdf5f"}; + consensus.defaultAssumeValid = uint256{}; + + pchMessageStart[0] = 0x1c; + pchMessageStart[1] = 0x16; + pchMessageStart[2] = 0x3f; + pchMessageStart[3] = 0x28; + nDefaultPort = 48333; + nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 0; + m_assumed_chain_state_size = 0; + + const char* testnet4_genesis_msg = "03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e"; + const CScript testnet4_genesis_script = CScript() << ParseHex("000000000000000000000000000000000000000000000000000000000000000000") << OP_CHECKSIG; + genesis = CreateGenesisBlock(testnet4_genesis_msg, + testnet4_genesis_script, + 1714777860, + 393743547, + 0x1d00ffff, + 1, + 50 * COIN); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043")); + assert(genesis.hashMerkleRoot == uint256S("0x7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e")); + + vFixedSeeds.clear(); + vSeeds.clear(); + // nodes with support for servicebits filtering should be at the top + vSeeds.emplace_back("seed.testnet4.bitcoin.sprovoost.nl."); // Sjors Provoost + vSeeds.emplace_back("seed.testnet4.wiz.biz."); // Jason Maurice + + 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_testnet4), std::end(chainparams_seed_testnet4)); + + fDefaultConsistencyChecks = false; + m_is_mockable_chain = false; + + checkpointData = { + { + {}, + } + }; + + m_assumeutxo_data = { + {} + }; + + chainTxData = ChainTxData{ + .nTime = 0, + .tx_count = 0, + .dTxRate = 0, + }; + } +}; + +/** * Signet: test network with an additional consensus parameter (see BIP325). */ class SigNetParams : public CChainParams { @@ -305,14 +420,14 @@ public: vSeeds.emplace_back("178.128.221.177"); vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333"); - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000206e86f08e8"); - consensus.defaultAssumeValid = uint256S("0x0000000870f15246ba23c16e370a7ffb1fc8a3dcf8cb4492882ed4b0e3d4cd26"); // 180000 + consensus.nMinimumChainWork = uint256{"00000000000000000000000000000000000000000000000000000206e86f08e8"}; + consensus.defaultAssumeValid = uint256{"0000000870f15246ba23c16e370a7ffb1fc8a3dcf8cb4492882ed4b0e3d4cd26"}; // 180000 m_assumed_blockchain_size = 1; m_assumed_chain_state_size = 0; chainTxData = ChainTxData{ // Data from RPC: getchaintxstats 4096 0000000870f15246ba23c16e370a7ffb1fc8a3dcf8cb4492882ed4b0e3d4cd26 .nTime = 1706331472, - .nTxCount = 2425380, + .tx_count = 2425380, .dTxRate = 0.008277759863833788, }; } else { @@ -346,11 +461,12 @@ public: consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; + consensus.enforce_BIP94 = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016 consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.MinBIP9WarningHeight = 0; - consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000"); + consensus.powLimit = uint256{"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; @@ -373,17 +489,17 @@ public: genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256{"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"}); + assert(genesis.hashMerkleRoot == uint256{"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"}); vFixedSeeds.clear(); m_assumeutxo_data = { { .height = 160'000, - .hash_serialized = AssumeutxoHash{uint256S("0xfe0a44309b74d6b5883d246cb419c6221bcccf0b308c9b59b7d70783dbdf928a")}, - .nChainTx = 2289496, - .blockhash = uint256S("0x0000003ca3c99aff040f2563c2ad8f8ec88bd0fd6b8f0895cfaf1ef90353a62c") + .hash_serialized = AssumeutxoHash{uint256{"fe0a44309b74d6b5883d246cb419c6221bcccf0b308c9b59b7d70783dbdf928a"}}, + .m_chain_tx_count = 2289496, + .blockhash = consteval_ctor(uint256{"0000003ca3c99aff040f2563c2ad8f8ec88bd0fd6b8f0895cfaf1ef90353a62c"}), } }; @@ -420,10 +536,11 @@ public: consensus.CSVHeight = 1; // Always active unless overridden consensus.SegwitHeight = 0; // Always active unless overridden consensus.MinBIP9WarningHeight = 0; - consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.powLimit = uint256{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; + consensus.enforce_BIP94 = false; consensus.fPowNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) @@ -478,8 +595,8 @@ public: genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); - assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); + assert(consensus.hashGenesisBlock == uint256{"0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"}); + assert(genesis.hashMerkleRoot == uint256{"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"}); vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. vSeeds.clear(); @@ -490,23 +607,30 @@ public: checkpointData = { { - {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")}, + {0, uint256{"0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"}}, } }; m_assumeutxo_data = { - { + { // For use by unit tests .height = 110, - .hash_serialized = AssumeutxoHash{uint256S("0x6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1")}, - .nChainTx = 111, - .blockhash = uint256S("0x696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c") + .hash_serialized = AssumeutxoHash{uint256{"6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1"}}, + .m_chain_tx_count = 111, + .blockhash = consteval_ctor(uint256{"696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c"}), + }, + { + // For use by fuzz target src/test/fuzz/utxo_snapshot.cpp + .height = 200, + .hash_serialized = AssumeutxoHash{uint256{"4f34d431c3e482f6b0d67b64609ece3964dc8d7976d02ac68dd7c9c1421738f2"}}, + .m_chain_tx_count = 201, + .blockhash = consteval_ctor(uint256{"5e93653318f294fb5aa339d00bbf8cf1c3515488ad99412c37608b139ea63b27"}), }, { // For use by test/functional/feature_assumeutxo.py .height = 299, - .hash_serialized = AssumeutxoHash{uint256S("0xa4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27")}, - .nChainTx = 334, - .blockhash = uint256S("0x3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0") + .hash_serialized = AssumeutxoHash{uint256{"a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27"}}, + .m_chain_tx_count = 334, + .blockhash = consteval_ctor(uint256{"3bb7ce5eba0be48939b7a521ac1ba9316afee2c7bada3a0cca24188e6d7d96c0"}), }, }; @@ -546,6 +670,11 @@ std::unique_ptr<const CChainParams> CChainParams::TestNet() return std::make_unique<const CTestNetParams>(); } +std::unique_ptr<const CChainParams> CChainParams::TestNet4() +{ + return std::make_unique<const CTestNet4Params>(); +} + std::vector<int> CChainParams::GetAvailableSnapshotHeights() const { std::vector<int> heights; @@ -561,6 +690,7 @@ std::optional<ChainType> GetNetworkForMagic(const MessageStartChars& message) { const auto mainnet_msg = CChainParams::Main()->MessageStart(); const auto testnet_msg = CChainParams::TestNet()->MessageStart(); + const auto testnet4_msg = CChainParams::TestNet4()->MessageStart(); const auto regtest_msg = CChainParams::RegTest({})->MessageStart(); const auto signet_msg = CChainParams::SigNet({})->MessageStart(); @@ -568,6 +698,8 @@ std::optional<ChainType> GetNetworkForMagic(const MessageStartChars& message) return ChainType::MAIN; } else if (std::equal(message.begin(), message.end(), testnet_msg.data())) { return ChainType::TESTNET; + } else if (std::equal(message.begin(), message.end(), testnet4_msg.data())) { + return ChainType::TESTNET4; } else if (std::equal(message.begin(), message.end(), regtest_msg.data())) { return ChainType::REGTEST; } else if (std::equal(message.begin(), message.end(), signet_msg.data())) { diff --git a/src/kernel/chainparams.h b/src/kernel/chainparams.h index 05ebd07ec7..c4584600fd 100644 --- a/src/kernel/chainparams.h +++ b/src/kernel/chainparams.h @@ -50,11 +50,11 @@ struct AssumeutxoData { //! The expected hash of the deserialized UTXO set. AssumeutxoHash hash_serialized; - //! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex(). + //! Used to populate the m_chain_tx_count 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. - unsigned int nChainTx; + uint64_t m_chain_tx_count; //! The hash of the base block for this snapshot. Used to refer to assumeutxo data //! prior to having a loaded blockindex. @@ -69,7 +69,7 @@ struct AssumeutxoData { */ 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 + uint64_t tx_count; //!< total number of transactions between genesis and that timestamp double dTxRate; //!< estimated number of transactions per second after that timestamp }; @@ -161,9 +161,10 @@ public: static std::unique_ptr<const CChainParams> SigNet(const SigNetOptions& options); static std::unique_ptr<const CChainParams> Main(); static std::unique_ptr<const CChainParams> TestNet(); + static std::unique_ptr<const CChainParams> TestNet4(); protected: - CChainParams() {} + CChainParams() = default; Consensus::Params consensus; MessageStartChars pchMessageStart; diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h index 076841c3c9..1b605f3d55 100644 --- a/src/kernel/chainstatemanager_opts.h +++ b/src/kernel/chainstatemanager_opts.h @@ -9,6 +9,7 @@ #include <arith_uint256.h> #include <dbwrapper.h> +#include <script/sigcache.h> #include <txdb.h> #include <uint256.h> #include <util/time.h> @@ -48,6 +49,8 @@ struct ChainstateManagerOpts { ValidationSignals* signals{nullptr}; //! Number of script check worker threads. Zero means no parallel verification. int worker_threads_num{0}; + size_t script_execution_cache_bytes{DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES}; + size_t signature_cache_bytes{DEFAULT_SIGNATURE_CACHE_BYTES}; }; } // namespace kernel diff --git a/src/kernel/context.cpp b/src/kernel/context.cpp index bfb17915fd..2420d18d74 100644 --- a/src/kernel/context.cpp +++ b/src/kernel/context.cpp @@ -8,15 +8,18 @@ #include <logging.h> #include <random.h> +#include <mutex> #include <string> - namespace kernel { Context::Context() { - std::string sha256_algo = SHA256AutoDetect(); - LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); - RandomInit(); + static std::once_flag globals_initialized{}; + std::call_once(globals_initialized, []() { + std::string sha256_algo = SHA256AutoDetect(); + LogInfo("Using the '%s' SHA256 implementation\n", sha256_algo); + RandomInit(); + }); } diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index 0850b2e60e..4e1e24a11d 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -22,7 +22,7 @@ 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 */ -static constexpr bool DEFAULT_MEMPOOL_FULL_RBF{false}; +static constexpr bool DEFAULT_MEMPOOL_FULL_RBF{true}; /** Whether to fall back to legacy V1 serialization when writing mempool.dat */ static constexpr bool DEFAULT_PERSIST_V1_DAT{false}; /** Default for -acceptnonstdtxn */ diff --git a/src/kernel/notifications_interface.h b/src/kernel/notifications_interface.h index 8e090dd7db..ef72d9bdb6 100644 --- a/src/kernel/notifications_interface.h +++ b/src/kernel/notifications_interface.h @@ -35,7 +35,7 @@ bool IsInterrupted(const T& result) class Notifications { public: - virtual ~Notifications(){}; + virtual ~Notifications() = default; [[nodiscard]] virtual InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) { return {}; } virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {} diff --git a/src/kernel/validation_cache_sizes.h b/src/kernel/validation_cache_sizes.h deleted file mode 100644 index 72e4d1a52c..0000000000 --- a/src/kernel/validation_cache_sizes.h +++ /dev/null @@ -1,20 +0,0 @@ -// 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_VALIDATION_CACHE_SIZES_H -#define BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H - -#include <script/sigcache.h> - -#include <cstddef> -#include <limits> - -namespace kernel { -struct ValidationCacheSizes { - size_t signature_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2}; - size_t script_execution_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2}; -}; -} - -#endif // BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H diff --git a/src/key.cpp b/src/key.cpp index 97d7821e74..360a1f46d3 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -271,27 +271,8 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const { - assert(sig.size() == 64); - secp256k1_keypair keypair; - if (!secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(begin()))) return false; - if (merkle_root) { - secp256k1_xonly_pubkey pubkey; - if (!secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, &keypair)) return false; - 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(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(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)); - return ret; + KeyPair kp = ComputeKeyPair(merkle_root); + return kp.SignSchnorr(hash, sig, aux); } bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) { @@ -363,6 +344,11 @@ ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, c return output; } +KeyPair CKey::ComputeKeyPair(const uint256* merkle_root) const +{ + return KeyPair(*this, merkle_root); +} + CKey GenerateRandomKey(bool compressed) noexcept { CKey key; @@ -420,6 +406,39 @@ void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { if ((nDepth == 0 && (nChild != 0 || ReadLE32(vchFingerprint) != 0)) || code[41] != 0) key = CKey(); } +KeyPair::KeyPair(const CKey& key, const uint256* merkle_root) +{ + static_assert(std::tuple_size<KeyType>() == sizeof(secp256k1_keypair)); + MakeKeyPairData(); + auto keypair = reinterpret_cast<secp256k1_keypair*>(m_keypair->data()); + bool success = secp256k1_keypair_create(secp256k1_context_sign, keypair, UCharCast(key.data())); + if (success && merkle_root) { + secp256k1_xonly_pubkey pubkey; + unsigned char pubkey_bytes[32]; + assert(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, keypair)); + assert(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)); + uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root); + success = secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, keypair, tweak.data()); + } + if (!success) ClearKeyPairData(); +} + +bool KeyPair::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256& aux) const +{ + assert(sig.size() == 64); + if (!IsValid()) return false; + auto keypair = reinterpret_cast<const secp256k1_keypair*>(m_keypair->data()); + 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(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()); + return ret; +} + bool ECC_InitSanityCheck() { CKey key = GenerateRandomKey(); CPubKey pubkey = key.GetPubKey(); @@ -28,6 +28,8 @@ constexpr static size_t ECDH_SECRET_SIZE = CSHA256::OUTPUT_SIZE; // Used to represent ECDH shared secret (ECDH_SECRET_SIZE bytes) using ECDHSecret = std::array<std::byte, ECDH_SECRET_SIZE>; +class KeyPair; + /** An encapsulated private key. */ class CKey { @@ -75,13 +77,15 @@ public: CKey& operator=(const CKey& other) { - if (other.keydata) { - MakeKeyData(); - *keydata = *other.keydata; - } else { - ClearKeyData(); + if (this != &other) { + if (other.keydata) { + MakeKeyData(); + *keydata = *other.keydata; + } else { + ClearKeyData(); + } + fCompressed = other.fCompressed; } - fCompressed = other.fCompressed; return *this; } @@ -200,6 +204,22 @@ public: ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, const EllSwiftPubKey& our_ellswift, bool initiating) const; + /** Compute a KeyPair + * + * Wraps a `secp256k1_keypair` type. + * + * `merkle_root` is used to optionally perform tweaking of + * the internal key, as specified in BIP341: + * + * - If merkle_root == nullptr: no tweaking is done, use the internal key directly (this is + * used for signatures in BIP342 script). + * - If merkle_root->IsNull(): tweak the internal key with H_TapTweak(pubkey) (this is used for + * key path spending when no scripts are present). + * - Otherwise: tweak the internal key with H_TapTweak(pubkey || *merkle_root) + * (this is used for key path spending with the + * Merkle root of the script tree). + */ + KeyPair ComputeKeyPair(const uint256* merkle_root) const; }; CKey GenerateRandomKey(bool compressed = true) noexcept; @@ -233,6 +253,61 @@ struct CExtKey { void SetSeed(Span<const std::byte> seed); }; +/** KeyPair + * + * Wraps a `secp256k1_keypair` type, an opaque data structure for holding a secret and public key. + * This is intended for BIP340 keys and allows us to easily determine if the secret key needs to + * be negated by checking the parity of the public key. This class primarily intended for passing + * secret keys to libsecp256k1 functions expecting a `secp256k1_keypair`. For all other cases, + * CKey should be preferred. + * + * A KeyPair can be created from a CKey with an optional merkle_root tweak (per BIP342). See + * CKey::ComputeKeyPair for more details. + */ +class KeyPair +{ +public: + KeyPair() noexcept = default; + KeyPair(KeyPair&&) noexcept = default; + KeyPair& operator=(KeyPair&&) noexcept = default; + KeyPair& operator=(const KeyPair& other) + { + if (this != &other) { + if (other.m_keypair) { + MakeKeyPairData(); + *m_keypair = *other.m_keypair; + } else { + ClearKeyPairData(); + } + } + return *this; + } + + KeyPair(const KeyPair& other) { *this = other; } + + friend KeyPair CKey::ComputeKeyPair(const uint256* merkle_root) const; + [[nodiscard]] bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256& aux) const; + + //! Check whether this keypair is valid. + bool IsValid() const { return !!m_keypair; } + +private: + KeyPair(const CKey& key, const uint256* merkle_root); + + using KeyType = std::array<unsigned char, 96>; + secure_unique_ptr<KeyType> m_keypair; + + void MakeKeyPairData() + { + if (!m_keypair) m_keypair = make_secure_unique<KeyType>(); + } + + void ClearKeyPairData() + { + m_keypair.reset(); + } +}; + /** Check that required EC support is available at runtime. */ bool ECC_InitSanityCheck(); diff --git a/src/key_io.cpp b/src/key_io.cpp index a373a2201d..29002afc45 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -181,6 +181,10 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return tap; } + if (CScript::IsPayToAnchor(version, data)) { + return PayToAnchor(); + } + if (version > 16) { error_str = "Invalid Bech32 address witness version"; return CNoDestination(); diff --git a/src/logging.cpp b/src/logging.cpp index a9fea433be..9a54a12b42 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <logging.h> +#include <memusage.h> #include <util/fs.h> #include <util/string.h> #include <util/threadnames.h> @@ -14,8 +15,7 @@ #include <optional> using util::Join; -using util::RemovePrefix; -using util::ToString; +using util::RemovePrefixView; const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL{BCLog::Level::Info}; @@ -43,7 +43,7 @@ BCLog::Logger& LogInstance() bool fLogIPs = DEFAULT_LOGIPS; -static int FileWriteStr(const std::string &str, FILE *fp) +static int FileWriteStr(std::string_view str, FILE *fp) { return fwrite(str.data(), 1, str.size(), fp); } @@ -71,17 +71,22 @@ bool BCLog::Logger::StartLogging() // dump buffered messages from before we opened the log m_buffering = false; + if (m_buffer_lines_discarded > 0) { + LogPrintStr_(strprintf("Early logging buffer overflowed, %d log lines discarded.\n", m_buffer_lines_discarded), __func__, __FILE__, __LINE__, BCLog::ALL, Level::Info); + } while (!m_msgs_before_open.empty()) { - const std::string& s = m_msgs_before_open.front(); + const auto& buflog = m_msgs_before_open.front(); + std::string s{buflog.str}; + FormatLogStrInPlace(s, buflog.category, buflog.level, buflog.source_file, buflog.source_line, buflog.logging_function, buflog.threadname, buflog.now, buflog.mocktime); + m_msgs_before_open.pop_front(); if (m_print_to_file) FileWriteStr(s, m_fileout); if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout); for (const auto& cb : m_print_callbacks) { cb(s); } - - m_msgs_before_open.pop_front(); } + m_cur_buffer_memusage = 0; if (m_print_to_console) fflush(stdout); return true; @@ -94,6 +99,23 @@ void BCLog::Logger::DisconnectTestLogger() if (m_fileout != nullptr) fclose(m_fileout); m_fileout = nullptr; m_print_callbacks.clear(); + m_max_buffer_memusage = DEFAULT_MAX_LOG_BUFFER; + m_cur_buffer_memusage = 0; + m_buffer_lines_discarded = 0; + m_msgs_before_open.clear(); + +} + +void BCLog::Logger::DisableLogging() +{ + { + StdLockGuard scoped_lock(m_cs); + assert(m_buffering); + assert(m_print_callbacks.empty()); + } + m_print_to_file = false; + m_print_to_console = false; + StartLogging(); } void BCLog::Logger::EnableCategory(BCLog::LogFlags flag) @@ -101,7 +123,7 @@ void BCLog::Logger::EnableCategory(BCLog::LogFlags flag) m_categories |= flag; } -bool BCLog::Logger::EnableCategory(const std::string& str) +bool BCLog::Logger::EnableCategory(std::string_view str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, str)) return false; @@ -114,7 +136,7 @@ void BCLog::Logger::DisableCategory(BCLog::LogFlags flag) m_categories &= ~flag; } -bool BCLog::Logger::DisableCategory(const std::string& str) +bool BCLog::Logger::DisableCategory(std::string_view str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, str)) return false; @@ -145,9 +167,7 @@ bool BCLog::Logger::DefaultShrinkDebugFile() const return m_categories == BCLog::NONE; } -static const std::map<std::string, BCLog::LogFlags> LOG_CATEGORIES_BY_STR{ - {"0", BCLog::NONE}, - {"", BCLog::NONE}, +static const std::map<std::string, BCLog::LogFlags, std::less<>> LOG_CATEGORIES_BY_STR{ {"net", BCLog::NET}, {"tor", BCLog::TOR}, {"mempool", BCLog::MEMPOOL}, @@ -179,28 +199,23 @@ static const std::map<std::string, BCLog::LogFlags> LOG_CATEGORIES_BY_STR{ {"txreconciliation", BCLog::TXRECONCILIATION}, {"scan", BCLog::SCAN}, {"txpackages", BCLog::TXPACKAGES}, - {"1", BCLog::ALL}, - {"all", BCLog::ALL}, }; static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{ // Swap keys and values from LOG_CATEGORIES_BY_STR. - [](const std::map<std::string, BCLog::LogFlags>& in) { + [](const auto& in) { std::unordered_map<BCLog::LogFlags, std::string> out; for (const auto& [k, v] : in) { - switch (v) { - case BCLog::NONE: out.emplace(BCLog::NONE, ""); break; - case BCLog::ALL: out.emplace(BCLog::ALL, "all"); break; - default: out.emplace(v, k); - } + const bool inserted{out.emplace(v, k).second}; + assert(inserted); } return out; }(LOG_CATEGORIES_BY_STR) }; -bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str) +bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str) { - if (str.empty()) { + if (str.empty() || str == "1" || str == "all") { flag = BCLog::ALL; return true; } @@ -229,14 +244,17 @@ std::string BCLog::Logger::LogLevelToStr(BCLog::Level level) assert(false); } -std::string LogCategoryToStr(BCLog::LogFlags category) +static std::string LogCategoryToStr(BCLog::LogFlags category) { + if (category == BCLog::ALL) { + return "all"; + } auto it = LOG_CATEGORIES_BY_FLAG.find(category); assert(it != LOG_CATEGORIES_BY_FLAG.end()); return it->second; } -static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str) +static std::optional<BCLog::Level> GetLogLevel(std::string_view level_str) { if (level_str == "trace") { return BCLog::Level::Trace; @@ -256,10 +274,9 @@ static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str) std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const { std::vector<LogCategory> ret; + ret.reserve(LOG_CATEGORIES_BY_STR.size()); for (const auto& [category, flag] : LOG_CATEGORIES_BY_STR) { - if (flag != BCLog::NONE && flag != BCLog::ALL) { - ret.push_back(LogCategory{.category = category, .active = WillLogCategory(flag)}); - } + ret.push_back(LogCategory{.category = category, .active = WillLogCategory(flag)}); } return ret; } @@ -276,28 +293,23 @@ std::string BCLog::Logger::LogLevelsString() const return Join(std::vector<BCLog::Level>{levels.begin(), levels.end()}, ", ", [](BCLog::Level level) { return LogLevelToStr(level); }); } -std::string BCLog::Logger::LogTimestampStr(const std::string& str) +std::string BCLog::Logger::LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const { std::string strStamped; if (!m_log_timestamps) - return str; - - if (m_started_new_line) { - const auto now{SystemClock::now()}; - const auto now_seconds{std::chrono::time_point_cast<std::chrono::seconds>(now)}; - strStamped = FormatISO8601DateTime(TicksSinceEpoch<std::chrono::seconds>(now_seconds)); - if (m_log_time_micros && !strStamped.empty()) { - strStamped.pop_back(); - strStamped += strprintf(".%06dZ", Ticks<std::chrono::microseconds>(now - now_seconds)); - } - std::chrono::seconds mocktime = GetMockTime(); - if (mocktime > 0s) { - strStamped += " (mocktime: " + FormatISO8601DateTime(count_seconds(mocktime)) + ")"; - } - strStamped += ' ' + str; - } else - strStamped = str; + return strStamped; + + const auto now_seconds{std::chrono::time_point_cast<std::chrono::seconds>(now)}; + strStamped = FormatISO8601DateTime(TicksSinceEpoch<std::chrono::seconds>(now_seconds)); + if (m_log_time_micros && !strStamped.empty()) { + strStamped.pop_back(); + strStamped += strprintf(".%06dZ", Ticks<std::chrono::microseconds>(now - now_seconds)); + } + if (mocktime > 0s) { + strStamped += " (mocktime: " + FormatISO8601DateTime(count_seconds(mocktime)) + ")"; + } + strStamped += ' '; return strStamped; } @@ -310,7 +322,7 @@ namespace BCLog { * It escapes instead of removes them to still allow for troubleshooting * issues where they accidentally end up in strings. */ - std::string LogEscapeMessage(const std::string& str) { + std::string LogEscapeMessage(std::string_view str) { std::string ret; for (char ch_in : str) { uint8_t ch = (uint8_t)ch_in; @@ -350,34 +362,84 @@ std::string BCLog::Logger::GetLogPrefix(BCLog::LogFlags category, BCLog::Level l return s; } -void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +static size_t MemUsage(const BCLog::Logger::BufferedLog& buflog) { - StdLockGuard scoped_lock(m_cs); - std::string str_prefixed = LogEscapeMessage(str); + return buflog.str.size() + buflog.logging_function.size() + buflog.source_file.size() + buflog.threadname.size() + memusage::MallocUsage(sizeof(memusage::list_node<BCLog::Logger::BufferedLog>)); +} - if (m_started_new_line) { - str_prefixed.insert(0, GetLogPrefix(category, level)); - } +void BCLog::Logger::FormatLogStrInPlace(std::string& str, BCLog::LogFlags category, BCLog::Level level, std::string_view source_file, int source_line, std::string_view logging_function, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const +{ + str.insert(0, GetLogPrefix(category, level)); - if (m_log_sourcelocations && m_started_new_line) { - str_prefixed.insert(0, "[" + RemovePrefix(source_file, "./") + ":" + ToString(source_line) + "] [" + logging_function + "] "); + if (m_log_sourcelocations) { + str.insert(0, strprintf("[%s:%d] [%s] ", RemovePrefixView(source_file, "./"), source_line, logging_function)); } - if (m_log_threadnames && m_started_new_line) { - const auto& threadname = util::ThreadGetInternalName(); - str_prefixed.insert(0, "[" + (threadname.empty() ? "unknown" : threadname) + "] "); + if (m_log_threadnames) { + str.insert(0, strprintf("[%s] ", (threadname.empty() ? "unknown" : threadname))); } - str_prefixed = LogTimestampStr(str_prefixed); + str.insert(0, LogTimestampStr(now, mocktime)); +} + +void BCLog::Logger::LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +{ + StdLockGuard scoped_lock(m_cs); + return LogPrintStr_(str, logging_function, source_file, source_line, category, level); +} +void BCLog::Logger::LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +{ + std::string str_prefixed = LogEscapeMessage(str); + + const bool starts_new_line = m_started_new_line; m_started_new_line = !str.empty() && str[str.size()-1] == '\n'; if (m_buffering) { - // buffer if we haven't started logging yet - m_msgs_before_open.push_back(str_prefixed); + if (!starts_new_line) { + if (!m_msgs_before_open.empty()) { + m_msgs_before_open.back().str += str_prefixed; + m_cur_buffer_memusage += str_prefixed.size(); + return; + } else { + // unlikely edge case; add a marker that something was trimmed + str_prefixed.insert(0, "[...] "); + } + } + + { + BufferedLog buf{ + .now=SystemClock::now(), + .mocktime=GetMockTime(), + .str=str_prefixed, + .logging_function=std::string(logging_function), + .source_file=std::string(source_file), + .threadname=util::ThreadGetInternalName(), + .source_line=source_line, + .category=category, + .level=level, + }; + m_cur_buffer_memusage += MemUsage(buf); + m_msgs_before_open.push_back(std::move(buf)); + } + + while (m_cur_buffer_memusage > m_max_buffer_memusage) { + if (m_msgs_before_open.empty()) { + m_cur_buffer_memusage = 0; + break; + } + m_cur_buffer_memusage -= MemUsage(m_msgs_before_open.front()); + m_msgs_before_open.pop_front(); + ++m_buffer_lines_discarded; + } + return; } + if (starts_new_line) { + FormatLogStrInPlace(str_prefixed, category, level, source_file, source_line, logging_function, util::ThreadGetInternalName(), SystemClock::now(), GetMockTime()); + } + if (m_print_to_console) { // print to console fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout); @@ -444,7 +506,7 @@ void BCLog::Logger::ShrinkDebugFile() fclose(file); } -bool BCLog::Logger::SetLogLevel(const std::string& level_str) +bool BCLog::Logger::SetLogLevel(std::string_view level_str) { const auto level = GetLogLevel(level_str); if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false; @@ -452,7 +514,7 @@ bool BCLog::Logger::SetLogLevel(const std::string& level_str) return true; } -bool BCLog::Logger::SetCategoryLogLevel(const std::string& category_str, const std::string& level_str) +bool BCLog::Logger::SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) { BCLog::LogFlags flag; if (!GetLogCategory(flag, category_str)) return false; diff --git a/src/logging.h b/src/logging.h index fe6b7051ba..2ff58979cb 100644 --- a/src/logging.h +++ b/src/logging.h @@ -10,6 +10,7 @@ #include <tinyformat.h> #include <util/fs.h> #include <util/string.h> +#include <util/time.h> #include <atomic> #include <cstdint> @@ -79,15 +80,29 @@ namespace BCLog { Error, }; constexpr auto DEFAULT_LOG_LEVEL{Level::Debug}; + constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging class Logger { + public: + struct BufferedLog { + SystemClock::time_point now; + std::chrono::seconds mocktime; + std::string str, logging_function, source_file, threadname; + int source_line; + LogFlags category; + Level level; + }; + private: mutable StdMutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected FILE* m_fileout GUARDED_BY(m_cs) = nullptr; - std::list<std::string> m_msgs_before_open GUARDED_BY(m_cs); + std::list<BufferedLog> m_msgs_before_open GUARDED_BY(m_cs); bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. + size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; + size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; + size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0}; /** * m_started_new_line is a state variable that will suppress printing of @@ -104,13 +119,21 @@ namespace BCLog { std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL}; /** Log categories bitfield. */ - std::atomic<uint32_t> m_categories{0}; + std::atomic<uint32_t> m_categories{BCLog::NONE}; - std::string LogTimestampStr(const std::string& str); + void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, std::string_view source_file, int source_line, std::string_view logging_function, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const; + + std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const; /** Slots that connect to the print signal */ std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs) {}; + /** Send a string to the log output (internal) */ + void LogPrintStr_(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + EXCLUSIVE_LOCKS_REQUIRED(m_cs); + + std::string GetLogPrefix(LogFlags category, Level level) const; + public: bool m_print_to_console = false; bool m_print_to_file = false; @@ -124,20 +147,19 @@ namespace BCLog { fs::path m_file_path; std::atomic<bool> m_reopen_file{false}; - std::string GetLogPrefix(LogFlags category, Level level) const; - /** Send a string to the log output */ - void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level); + void LogPrintStr(std::string_view str, std::string_view logging_function, std::string_view source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Returns whether logs will be written to any output */ - bool Enabled() const + bool Enabled() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty(); } /** Connect a slot to the print signal and return the connection */ - std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) + std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_print_callbacks.push_back(std::move(fun)); @@ -145,44 +167,52 @@ namespace BCLog { } /** Delete a connection */ - void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) + void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_print_callbacks.erase(it); } /** Start logging (and flush all buffered messages) */ - bool StartLogging(); + bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Only for testing */ - void DisconnectTestLogger(); + void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); + + /** Disable logging + * This offers a slight speedup and slightly smaller memory usage + * compared to leaving the logging system in its default state. + * Mostly intended for libbitcoin-kernel apps that don't want any logging. + * Should be used instead of StartLogging(). + */ + void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs); void ShrinkDebugFile(); - std::unordered_map<LogFlags, Level> CategoryLevels() const + std::unordered_map<LogFlags, Level> CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); return m_category_log_levels; } - void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels) + void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs) { StdLockGuard scoped_lock(m_cs); m_category_log_levels = levels; } - bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str); + bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs); Level LogLevel() const { return m_log_level.load(); } void SetLogLevel(Level level) { m_log_level = level; } - bool SetLogLevel(const std::string& level); + bool SetLogLevel(std::string_view level); uint32_t GetCategoryMask() const { return m_categories.load(); } void EnableCategory(LogFlags flag); - bool EnableCategory(const std::string& str); + bool EnableCategory(std::string_view str); void DisableCategory(LogFlags flag); - bool DisableCategory(const std::string& str); + bool DisableCategory(std::string_view str); bool WillLogCategory(LogFlags category) const; - bool WillLogCategoryLevel(LogFlags category, Level level) const; + bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs); /** Returns a vector of the log categories in alphabetical order. */ std::vector<LogCategory> LogCategoriesList() const; @@ -212,14 +242,14 @@ static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level leve } /** Return true if str parses as a log category and set the flag */ -bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); +bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str); // Be conservative when using functions that // unconditionally log to debug.log! It should not be the case that an inbound // peer can fill up a user's disk with debug.log entries. template <typename... Args> -static inline void LogPrintf_(const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, const char* fmt, const Args&... args) +static inline void LogPrintf_(std::string_view logging_function, std::string_view source_file, const int source_line, const BCLog::LogFlags flag, const BCLog::Level level, const char* fmt, const Args&... args) { if (LogInstance().Enabled()) { std::string log_msg; diff --git a/src/merkleblock.h b/src/merkleblock.h index 12b41a581e..945b7d3341 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -147,7 +147,7 @@ public: // Create from a CBlock, matching the txids in the set CMerkleBlock(const CBlock& block, const std::set<Txid>& txids) : CMerkleBlock{block, nullptr, &txids} {} - CMerkleBlock() {} + CMerkleBlock() = default; SERIALIZE_METHODS(CMerkleBlock, obj) { READWRITE(obj.header, obj.txn); } diff --git a/src/net.cpp b/src/net.cpp index 990c58ee3d..e1206745a4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -415,7 +415,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo if (pszDest) { std::vector<CService> resolved{Lookup(pszDest, default_port, fNameLookup && !HaveNameProxy(), 256)}; if (!resolved.empty()) { - Shuffle(resolved.begin(), resolved.end(), FastRandomContext()); + std::shuffle(resolved.begin(), resolved.end(), FastRandomContext()); // If the connection is made by name, it can be the case that the name resolves to more than one address. // We don't want to connect any more of them if we are already connected to one for (const auto& r : resolved) { @@ -576,16 +576,14 @@ CService CNode::GetAddrLocal() const { AssertLockNotHeld(m_addr_local_mutex); LOCK(m_addr_local_mutex); - return addrLocal; + return m_addr_local; } void CNode::SetAddrLocal(const CService& addrLocalIn) { AssertLockNotHeld(m_addr_local_mutex); LOCK(m_addr_local_mutex); - if (addrLocal.IsValid()) { - LogError("Addr local already set for node: %i. Refusing to change from %s to %s\n", id, addrLocal.ToStringAddrPort(), addrLocalIn.ToStringAddrPort()); - } else { - addrLocal = addrLocalIn; + if (Assume(!m_addr_local.IsValid())) { // Addr local can only be set once during version msg processing + m_addr_local = addrLocalIn; } } @@ -1810,13 +1808,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, }); pnode->AddRef(); m_msgproc->InitializeNode(*pnode, nLocalServices); - - LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToStringAddrPort()); - { LOCK(m_nodes_mutex); m_nodes.push_back(pnode); } + LogDebug(BCLog::NET, "connection from %s accepted\n", addr.ToStringAddrPort()); // We received a new connection, harvest entropy from the time (and our peer count) RandAddEvent((uint32_t)id); @@ -1983,7 +1979,11 @@ bool CConnman::InactivityCheck(const CNode& node) const } if (!node.fSuccessfullyConnected) { - LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId()); + if (node.m_transport->GetInfo().transport_type == TransportProtocolType::DETECTING) { + LogPrint(BCLog::NET, "V2 handshake timeout peer=%d\n", node.GetId()); + } else { + LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId()); + } return true; } @@ -2208,7 +2208,7 @@ void CConnman::ThreadDNSAddressSeed() FastRandomContext rng; std::vector<std::string> seeds = m_params.DNSSeeds(); - Shuffle(seeds.begin(), seeds.end(), rng); + std::shuffle(seeds.begin(), seeds.end(), rng); int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) { @@ -2435,7 +2435,7 @@ bool CConnman::MultipleManualOrFullOutboundConns(Network net) const bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network) { std::array<Network, 5> nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS}; - Shuffle(nets.begin(), nets.end(), FastRandomContext()); + std::shuffle(nets.begin(), nets.end(), FastRandomContext()); LOCK(m_nodes_mutex); for (const auto net : nets) { @@ -2481,9 +2481,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) auto start = GetTime<std::chrono::microseconds>(); // Minimum time before next feeler connection (in microseconds). - auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL); - auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); - auto next_extra_network_peer{GetExponentialRand(start, EXTRA_NETWORK_PEER_INTERVAL)}; + auto next_feeler = start + rng.rand_exp_duration(FEELER_INTERVAL); + auto next_extra_block_relay = start + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); + auto next_extra_network_peer{start + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL)}; const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED); bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS); const bool use_seednodes{gArgs.IsArgSet("-seednode")}; @@ -2642,10 +2642,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // Because we can promote these connections to block-relay-only // connections, they do not get their own ConnectionType enum // (similar to how we deal with extra outbound peers). - next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); + next_extra_block_relay = now + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); conn_type = ConnectionType::BLOCK_RELAY; } else if (now > next_feeler) { - next_feeler = GetExponentialRand(now, FEELER_INTERVAL); + next_feeler = now + rng.rand_exp_duration(FEELER_INTERVAL); conn_type = ConnectionType::FEELER; fFeeler = true; } else if (nOutboundFullRelay == m_max_outbound_full_relay && @@ -2658,7 +2658,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // This is not attempted if the user changed -maxconnections to a value // so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made, // to prevent interactions with otherwise protected outbound peers. - next_extra_network_peer = GetExponentialRand(now, EXTRA_NETWORK_PEER_INTERVAL); + next_extra_network_peer = now + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL); } else { // skip to next iteration of while loop continue; @@ -3198,24 +3198,36 @@ bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlag bool CConnman::InitBinds(const Options& options) { - bool fBound = false; for (const auto& addrBind : options.vBinds) { - fBound |= Bind(addrBind, BF_REPORT_ERROR, NetPermissionFlags::None); + if (!Bind(addrBind, BF_REPORT_ERROR, NetPermissionFlags::None)) { + return false; + } } for (const auto& addrBind : options.vWhiteBinds) { - fBound |= Bind(addrBind.m_service, BF_REPORT_ERROR, addrBind.m_flags); + if (!Bind(addrBind.m_service, BF_REPORT_ERROR, addrBind.m_flags)) { + return false; + } } for (const auto& addr_bind : options.onion_binds) { - fBound |= Bind(addr_bind, BF_DONT_ADVERTISE, NetPermissionFlags::None); + if (!Bind(addr_bind, BF_REPORT_ERROR | BF_DONT_ADVERTISE, NetPermissionFlags::None)) { + return false; + } } if (options.bind_on_any) { + // Don't consider errors to bind on IPv6 "::" fatal because the host OS + // may not have IPv6 support and the user did not explicitly ask us to + // bind on that. + const CService ipv6_any{in6_addr(IN6ADDR_ANY_INIT), GetListenPort()}; // :: + Bind(ipv6_any, BF_NONE, NetPermissionFlags::None); + struct in_addr inaddr_any; inaddr_any.s_addr = htonl(INADDR_ANY); - struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT; - fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::None); - fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::None); + const CService ipv4_any{inaddr_any, GetListenPort()}; // 0.0.0.0 + if (!Bind(ipv4_any, BF_REPORT_ERROR, NetPermissionFlags::None)) { + return false; + } } - return fBound; + return true; } bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) @@ -3475,7 +3487,8 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days, // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference // in terms of the freshness of the response. - cache_entry.m_cache_entry_expiration = current_time + std::chrono::hours(21) + GetRandMillis(std::chrono::hours(6)); + cache_entry.m_cache_entry_expiration = current_time + + 21h + FastRandomContext().randrange<std::chrono::microseconds>(6h); } return cache_entry.m_addrs_response_cache; } @@ -3533,6 +3546,13 @@ size_t CConnman::GetNodeCount(ConnectionDirection flags) const return nNum; } + +std::map<CNetAddr, LocalServiceInfo> CConnman::getNetLocalAddresses() const +{ + LOCK(g_maplocalhost_mutex); + return mapLocalHost; +} + uint32_t CConnman::GetMappedAS(const CNetAddr& addr) const { return m_netgroupman.GetMappedAS(addr); @@ -250,7 +250,7 @@ public: /** The Transport converts one connection's sent messages to wire bytes, and received bytes back. */ class Transport { public: - virtual ~Transport() {} + virtual ~Transport() = default; struct Info { @@ -963,7 +963,7 @@ private: size_t m_msg_process_queue_size GUARDED_BY(m_msg_process_queue_mutex){0}; // Our address, as reported by the peer - CService addrLocal GUARDED_BY(m_addr_local_mutex); + CService m_addr_local GUARDED_BY(m_addr_local_mutex); mutable Mutex m_addr_local_mutex; mapMsgTypeSize mapSendBytesPerMsgType GUARDED_BY(cs_vSend); @@ -991,8 +991,8 @@ public: /** Mutex for anything that is only accessed via the msg processing thread */ static Mutex g_msgproc_mutex; - /** Initialize a peer (setup state, queue any initial messages) */ - virtual void InitializeNode(CNode& node, ServiceFlags our_services) = 0; + /** Initialize a peer (setup state) */ + virtual void InitializeNode(const CNode& node, ServiceFlags our_services) = 0; /** Handle removal of a peer (clear state) */ virtual void FinalizeNode(const CNode& node) = 0; @@ -1205,6 +1205,7 @@ public: bool AddConnection(const std::string& address, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex); size_t GetNodeCount(ConnectionDirection) const; + std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() const; uint32_t GetMappedAS(const CNetAddr& addr) const; void GetNodeStats(std::vector<CNodeStats>& vstats) const; bool DisconnectNode(const std::string& node); @@ -1625,7 +1626,7 @@ private: } } if (shuffle) { - Shuffle(m_nodes_copy.begin(), m_nodes_copy.end(), FastRandomContext{}); + std::shuffle(m_nodes_copy.begin(), m_nodes_copy.end(), FastRandomContext{}); } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 3be4479587..13ea3a29be 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -32,7 +32,6 @@ #include <primitives/block.h> #include <primitives/transaction.h> #include <random.h> -#include <reverse_iterator.h> #include <scheduler.h> #include <streams.h> #include <sync.h> @@ -51,6 +50,7 @@ #include <future> #include <memory> #include <optional> +#include <ranges> #include <typeinfo> #include <utility> @@ -243,6 +243,9 @@ struct Peer { * Most peers use headers-first syncing, which doesn't use this mechanism */ uint256 m_continuation_block GUARDED_BY(m_block_inv_mutex) {}; + /** Set to true once initial VERSION message was sent (only relevant for outbound peers). */ + bool m_outbound_version_message_sent GUARDED_BY(NetEventsInterface::g_msgproc_mutex){false}; + /** This peer's reported block height when we connected */ std::atomic<int> m_starting_height{-1}; @@ -486,10 +489,12 @@ public: CTxMemPool& pool, node::Warnings& warnings, Options opts); /** Overridden from CValidationInterface. */ + void ActiveTipChange(const CBlockIndex& new_tip, bool) override + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override - EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void BlockChecked(const CBlock& block, const BlockValidationState& state) override @@ -498,13 +503,13 @@ public: EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); /** Implement NetEventsInterface */ - void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex); + void InitializeNode(const CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_tx_download_mutex); + void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex, !m_tx_download_mutex); bool HasAllDesirableServiceFlags(ServiceFlags services) const override; bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); bool SendMessages(CNode* pto) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, g_msgproc_mutex, !m_tx_download_mutex); /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; @@ -523,7 +528,7 @@ public: void UnitTestMisbehaving(NodeId peer_id) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex) { Misbehaving(*Assert(GetPeerRef(peer_id)), ""); }; void ProcessMessage(CNode& pfrom, const std::string& msg_type, DataStream& vRecv, const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex, !m_tx_download_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override; @@ -579,15 +584,15 @@ private: * @param[in] maybe_add_extra_compact_tx Whether this tx should be added to vExtraTxnForCompact. * Set to false if the tx has already been rejected before, * e.g. is an orphan, to avoid adding duplicate entries. - * Updates m_txrequest, m_recent_rejects, m_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */ + * Updates m_txrequest, m_lazy_recent_rejects, m_lazy_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */ void ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result, bool maybe_add_extra_compact_tx) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** Handle a transaction whose result was MempoolAcceptResult::ResultType::VALID. * Updates m_txrequest, m_orphanage, and vExtraTxnForCompact. Also queues the tx for relay. */ void ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); struct PackageToValidate { const Package m_txns; @@ -617,13 +622,13 @@ private: * individual transactions, and caches rejection for the package as a group. */ void ProcessPackageResult(const PackageToValidate& package_to_validate, const PackageMempoolAcceptResult& package_result) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package, * skipping any combinations that have already been tried. Return the resulting package along with * the senders of its respective transactions, or std::nullopt if no package is found. */ std::optional<PackageToValidate> Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex); /** * Reconsider orphan transactions after a parent has been accepted to the mempool. @@ -637,7 +642,7 @@ private: * will be empty. */ bool ProcessOrphanTx(Peer& peer) - EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, !m_tx_download_mutex); /** Process a single headers message from a peer. * @@ -719,7 +724,7 @@ private: * peer. The announcement parameters are decided in PeerManager and then * passed to TxRequestTracker. */ void AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) - EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_tx_download_mutex); /** Send a message to a peer */ void PushMessage(CNode& node, CSerializedNetMsg&& msg) const { m_connman.PushMessage(&node, std::move(msg)); } @@ -767,7 +772,17 @@ private: BanMan* const m_banman; ChainstateManager& m_chainman; CTxMemPool& m_mempool; - TxRequestTracker m_txrequest GUARDED_BY(::cs_main); + + /** Synchronizes tx download including TxRequestTracker, rejection filters, and TxOrphanage. + * Lock invariants: + * - A txhash (txid or wtxid) in m_txrequest is not also in m_orphanage. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_rejects. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_rejects_reconsiderable. + * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_confirmed_transactions. + * - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc). + */ + Mutex m_tx_download_mutex ACQUIRED_BEFORE(m_mempool.cs); + TxRequestTracker m_txrequest GUARDED_BY(m_tx_download_mutex); std::unique_ptr<TxReconciliationTracker> m_txreconciliation; /** The height of the best chain */ @@ -841,14 +856,12 @@ private: /** Check whether we already have this gtxid in: * - mempool * - orphanage - * - m_recent_rejects - * - m_recent_rejects_reconsiderable (if include_reconsiderable = true) - * - m_recent_confirmed_transactions - * Also responsible for resetting m_recent_rejects and m_recent_rejects_reconsiderable if the - * chain tip has changed. + * - m_lazy_recent_rejects + * - m_lazy_recent_rejects_reconsiderable (if include_reconsiderable = true) + * - m_lazy_recent_confirmed_transactions * */ bool AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex); + EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex); /** * Filter for transactions that were recently rejected by the mempool. @@ -884,10 +897,18 @@ private: * * Memory used: 1.3 MB */ - CRollingBloomFilter m_recent_rejects GUARDED_BY(::cs_main){120'000, 0.000'001}; - /** Block hash of chain tip the last time we reset m_recent_rejects and - * m_recent_rejects_reconsiderable. */ - uint256 hashRecentRejectsChainTip GUARDED_BY(cs_main); + std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects GUARDED_BY(m_tx_download_mutex){nullptr}; + + CRollingBloomFilter& RecentRejectsFilter() EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex) + { + AssertLockHeld(m_tx_download_mutex); + + if (!m_lazy_recent_rejects) { + m_lazy_recent_rejects = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001); + } + + return *m_lazy_recent_rejects; + } /** * Filter for: @@ -895,7 +916,7 @@ private: * eligible for reconsideration if submitted with other transactions. * (2) packages (see GetPackageHash) we have already rejected before and should not retry. * - * Similar to m_recent_rejects, this filter is used to save bandwidth when e.g. all of our peers + * Similar to m_lazy_recent_rejects, this filter is used to save bandwidth when e.g. all of our peers * have larger mempools and thus lower minimum feerates than us. * * When a transaction's error is TxValidationResult::TX_RECONSIDERABLE (in a package or by @@ -907,9 +928,20 @@ private: * * Reset this filter when the chain tip changes. * - * Parameters are picked to be the same as m_recent_rejects, with the same rationale. + * Parameters are picked to be the same as m_lazy_recent_rejects, with the same rationale. */ - CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY(::cs_main){120'000, 0.000'001}; + std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects_reconsiderable GUARDED_BY(m_tx_download_mutex){nullptr}; + + CRollingBloomFilter& RecentRejectsReconsiderableFilter() EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex) + { + AssertLockHeld(m_tx_download_mutex); + + if (!m_lazy_recent_rejects_reconsiderable) { + m_lazy_recent_rejects_reconsiderable = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001); + } + + return *m_lazy_recent_rejects_reconsiderable; + } /* * Filter for transactions that have been recently confirmed. @@ -926,8 +958,18 @@ private: * transaction per day that would be inadvertently ignored (which is the * same probability that we have in the reject filter). */ - Mutex m_recent_confirmed_transactions_mutex; - CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY(m_recent_confirmed_transactions_mutex){48'000, 0.000'001}; + std::unique_ptr<CRollingBloomFilter> m_lazy_recent_confirmed_transactions GUARDED_BY(m_tx_download_mutex){nullptr}; + + CRollingBloomFilter& RecentConfirmedTransactionsFilter() EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex) + { + AssertLockHeld(m_tx_download_mutex); + + if (!m_lazy_recent_confirmed_transactions) { + m_lazy_recent_confirmed_transactions = std::make_unique<CRollingBloomFilter>(48'000, 0.000'001); + } + + return *m_lazy_recent_confirmed_transactions; + } /** * For sending `inv`s to inbound peers, we use a single (exponentially @@ -936,7 +978,7 @@ private: * accurately determine when we received the transaction (and potentially * determine the transaction's origin). */ std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now, - std::chrono::seconds average_interval); + std::chrono::seconds average_interval) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); // All of the following cache a recent block, and are protected by m_most_recent_block_mutex @@ -1064,7 +1106,7 @@ private: int m_peers_downloading_from GUARDED_BY(cs_main) = 0; /** Storage for orphan information */ - TxOrphanage m_orphanage; + TxOrphanage m_orphanage GUARDED_BY(m_tx_download_mutex); void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex); @@ -1096,7 +1138,7 @@ private: bool BlockRequestAllowed(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv) - EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); + EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex, !m_most_recent_block_mutex); /** * Validation logic for compact filters request handling. @@ -1244,7 +1286,7 @@ std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::micros // If this function were called from multiple threads simultaneously // it would possible that both update the next send variable, and return a different result to their caller. // This is not possible in practice as only the net processing thread invokes this function. - m_next_inv_to_inbounds = GetExponentialRand(now, average_interval); + m_next_inv_to_inbounds = now + m_rng.rand_exp_duration(average_interval); } return m_next_inv_to_inbounds; } @@ -1476,9 +1518,20 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co return; } - if (state->pindexLastCommonBlock == nullptr) { - // Bootstrap quickly by guessing a parent of our best tip is the forking point. - // Guessing wrong in either direction is not a problem. + // When we sync with AssumeUtxo and discover the snapshot is not in the peer's best chain, abort: + // We can't reorg to this chain due to missing undo data until the background sync has finished, + // so downloading blocks from it would be futile. + const CBlockIndex* snap_base{m_chainman.GetSnapshotBaseBlock()}; + if (snap_base && state->pindexBestKnownBlock->GetAncestor(snap_base->nHeight) != snap_base) { + LogDebug(BCLog::NET, "Not downloading blocks from peer=%d, which doesn't have the snapshot block in its best chain.\n", peer.m_id); + return; + } + + // Bootstrap quickly by guessing a parent of our best tip is the forking point. + // Guessing wrong in either direction is not a problem. + // Also reset pindexLastCommonBlock after a snapshot was loaded, so that blocks after the snapshot will be prioritised for download. + if (state->pindexLastCommonBlock == nullptr || + (snap_base && state->pindexLastCommonBlock->nHeight < snap_base->nHeight)) { state->pindexLastCommonBlock = m_chainman.ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight, m_chainman.ActiveChain().Height())]; } @@ -1627,7 +1680,8 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer) void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) { - AssertLockHeld(::cs_main); // For m_txrequest + AssertLockHeld(::cs_main); // for State + AssertLockHeld(m_tx_download_mutex); // For m_txrequest NodeId nodeid = node.GetId(); if (!node.HasPermission(NetPermissionFlags::Relay) && m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) { // Too many queued announcements from this peer @@ -1659,12 +1713,15 @@ void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_s if (state) state->m_last_block_announcement = time_in_seconds; } -void PeerManagerImpl::InitializeNode(CNode& node, ServiceFlags our_services) +void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_services) { NodeId nodeid = node.GetId(); { - LOCK(cs_main); + LOCK(cs_main); // For m_node_states m_node_states.emplace_hint(m_node_states.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(node.IsInboundConn())); + } + { + LOCK(m_tx_download_mutex); assert(m_txrequest.Count(nodeid) == 0); } @@ -1677,9 +1734,6 @@ void PeerManagerImpl::InitializeNode(CNode& node, ServiceFlags our_services) LOCK(m_peer_mutex); m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer); } - if (!node.IsInboundConn()) { - PushNodeVersion(node, *peer); - } } void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) @@ -1698,7 +1752,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) // Schedule next run for 10-15 minutes in the future. // We add randomness on every cycle to avoid the possibility of P2P fingerprinting. - const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); + const auto delta = 10min + FastRandomContext().randrange<std::chrono::milliseconds>(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -1735,8 +1789,11 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) } } } - m_orphanage.EraseForPeer(nodeid); - m_txrequest.DisconnectedPeer(nodeid); + { + LOCK(m_tx_download_mutex); + 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->vBlocksInFlight.empty()); @@ -1753,6 +1810,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) assert(m_peers_downloading_from == 0); assert(m_outbound_peers_with_protect_from_disconnect == 0); assert(m_wtxid_relay_peers == 0); + LOCK(m_tx_download_mutex); assert(m_txrequest.Size() == 0); assert(m_orphanage.Size() == 0); } @@ -2050,10 +2108,27 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL}); // schedule next run for 10-15 minutes in the future - const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); + const auto delta = 10min + FastRandomContext().randrange<std::chrono::milliseconds>(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } +void PeerManagerImpl::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd) +{ + // Ensure mempool mutex was released, otherwise deadlock may occur if another thread holding + // m_tx_download_mutex waits on the mempool mutex. + AssertLockNotHeld(m_mempool.cs); + AssertLockNotHeld(m_tx_download_mutex); + + if (!is_ibd) { + LOCK(m_tx_download_mutex); + // If the chain tip has changed, previously rejected transactions might now be valid, e.g. due + // to a timelock. Reset the rejection filters to give those transactions another chance if we + // see them again. + RecentRejectsFilter().reset(); + RecentRejectsReconsiderableFilter().reset(); + } +} + /** * Evict orphan txn pool entries based on a newly connected * block, remember the recently confirmed transactions, and delete tracked @@ -2084,23 +2159,16 @@ void PeerManagerImpl::BlockConnected( if (role == ChainstateRole::BACKGROUND) { return; } + LOCK(m_tx_download_mutex); m_orphanage.EraseForBlock(*pblock); - { - LOCK(m_recent_confirmed_transactions_mutex); - for (const auto& ptx : pblock->vtx) { - m_recent_confirmed_transactions.insert(ptx->GetHash().ToUint256()); - if (ptx->HasWitness()) { - m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256()); - } - } - } - { - LOCK(cs_main); - for (const auto& ptx : pblock->vtx) { - m_txrequest.ForgetTxHash(ptx->GetHash()); - m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); + for (const auto& ptx : pblock->vtx) { + RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256()); + if (ptx->HasWitness()) { + RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256()); } + m_txrequest.ForgetTxHash(ptx->GetHash()); + m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); } } @@ -2114,8 +2182,8 @@ void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &blo // block's worth of transactions in it, but that should be fine, since // presumably the most common case of relaying a confirmed transaction // should be just after a new block containing it is found. - LOCK(m_recent_confirmed_transactions_mutex); - m_recent_confirmed_transactions.reset(); + LOCK(m_tx_download_mutex); + RecentConfirmedTransactionsFilter().reset(); } /** @@ -2124,7 +2192,7 @@ void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &blo */ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) { - auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock, GetRand<uint64_t>()); + auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock, FastRandomContext().rand64()); LOCK(cs_main); @@ -2202,7 +2270,7 @@ void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlock for (auto& it : m_peer_map) { Peer& peer = *it.second; LOCK(peer.m_block_inv_mutex); - for (const uint256& hash : reverse_iterate(vHashes)) { + for (const uint256& hash : vHashes | std::views::reverse) { peer.m_blocks_for_headers_relay.push_back(hash); } } @@ -2254,15 +2322,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) { - if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { - // If the chain tip has changed previously rejected transactions - // might be now valid, e.g. due to a nLockTime'd tx becoming valid, - // or a double-spend. Reset the rejects filter and give those - // txs a second chance. - hashRecentRejectsChainTip = m_chainman.ActiveChain().Tip()->GetBlockHash(); - m_recent_rejects.reset(); - m_recent_rejects_reconsiderable.reset(); - } + AssertLockHeld(m_tx_download_mutex); const uint256& hash = gtxid.GetHash(); @@ -2284,14 +2344,11 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconside if (m_orphanage.HaveTx(Wtxid::FromUint256(hash))) return true; } - if (include_reconsiderable && m_recent_rejects_reconsiderable.contains(hash)) return true; + if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true; - { - LOCK(m_recent_confirmed_transactions_mutex); - if (m_recent_confirmed_transactions.contains(hash)) return true; - } + if (RecentConfirmedTransactionsFilter().contains(hash)) return true; - return m_recent_rejects.contains(hash) || m_mempool.exists(gtxid); + return RecentRejectsFilter().contains(hash) || m_mempool.exists(gtxid); } bool PeerManagerImpl::AlreadyHaveBlock(const uint256& block_hash) @@ -2522,7 +2579,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& if (a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { MakeAndPushMessage(pfrom, NetMsgType::CMPCTBLOCK, *a_recent_compact_block); } else { - CBlockHeaderAndShortTxIDs cmpctblock{*pblock, GetRand<uint64_t>()}; + CBlockHeaderAndShortTxIDs cmpctblock{*pblock, m_rng.rand64()}; MakeAndPushMessage(pfrom, NetMsgType::CMPCTBLOCK, cmpctblock); } } else { @@ -2912,7 +2969,7 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c } else { std::vector<CInv> vGetData; // Download as much as possible, from earliest to latest. - for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { + for (const CBlockIndex* pindex : vToFetch | std::views::reverse) { if (nodestate->vBlocksInFlight.size() >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { // Can't download any more from this peer break; @@ -3154,7 +3211,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n", ptx->GetHash().ToString(), @@ -3179,12 +3236,12 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx // for concerns around weakening security of unupgraded nodes // if we start doing this too early. if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) { - // If the result is TX_RECONSIDERABLE, add it to m_recent_rejects_reconsiderable + // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable // because we should not download or submit this transaction by itself again, but may // submit it as part of a package later. - m_recent_rejects_reconsiderable.insert(ptx->GetWitnessHash().ToUint256()); + RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256()); } else { - m_recent_rejects.insert(ptx->GetWitnessHash().ToUint256()); + RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256()); } m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); // If the transaction failed for TX_INPUTS_NOT_STANDARD, @@ -3198,7 +3255,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx // We only add the txid if it differs from the wtxid, to avoid wasting entries in the // rolling bloom filter. if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) { - m_recent_rejects.insert(ptx->GetHash().ToUint256()); + RecentRejectsFilter().insert(ptx->GetHash().ToUint256()); m_txrequest.ForgetTxHash(ptx->GetHash()); } if (maybe_add_extra_compact_tx && RecursiveDynamicUsage(*ptx) < 100000) { @@ -3219,7 +3276,7 @@ void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, c { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); // As this version of the transaction was acceptable, we can forget about any requests for it. // No-op if the tx is not in txrequest. @@ -3247,13 +3304,13 @@ void PeerManagerImpl::ProcessPackageResult(const PackageToValidate& package_to_v { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); const auto& package = package_to_validate.m_txns; const auto& senders = package_to_validate.m_senders; if (package_result.m_state.IsInvalid()) { - m_recent_rejects_reconsiderable.insert(GetPackageHash(package)); + RecentRejectsReconsiderableFilter().insert(GetPackageHash(package)); } // We currently only expect to process 1-parent-1-child packages. Remove if this changes. if (!Assume(package.size() == 2)) return; @@ -3303,11 +3360,11 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka { AssertLockNotHeld(m_peer_mutex); AssertLockHeld(g_msgproc_mutex); - AssertLockHeld(cs_main); + AssertLockHeld(m_tx_download_mutex); const auto& parent_wtxid{ptx->GetWitnessHash()}; - Assume(m_recent_rejects_reconsiderable.contains(parent_wtxid.ToUint256())); + Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256())); // Prefer children from this peer. This helps prevent censorship attempts in which an attacker // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake @@ -3319,7 +3376,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka // most recent) one efficiently. for (const auto& child : cpfp_candidates_same_peer) { Package maybe_cpfp_package{ptx, child}; - if (!m_recent_rejects_reconsiderable.contains(GetPackageHash(maybe_cpfp_package))) { + if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package))) { return PeerManagerImpl::PackageToValidate{ptx, child, nodeid, nodeid}; } } @@ -3339,14 +3396,14 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka // Create a random permutation of the indices. std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size()); std::iota(tx_indices.begin(), tx_indices.end(), 0); - Shuffle(tx_indices.begin(), tx_indices.end(), m_rng); + std::shuffle(tx_indices.begin(), tx_indices.end(), m_rng); for (const auto index : tx_indices) { // If we already tried a package and failed for any reason, the combined hash was - // cached in m_recent_rejects_reconsiderable. + // cached in m_lazy_recent_rejects_reconsiderable. const auto [child_tx, child_sender] = cpfp_candidates_different_peer.at(index); Package maybe_cpfp_package{ptx, child_tx}; - if (!m_recent_rejects_reconsiderable.contains(GetPackageHash(maybe_cpfp_package))) { + if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package))) { return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid, child_sender}; } } @@ -3356,7 +3413,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka bool PeerManagerImpl::ProcessOrphanTx(Peer& peer) { AssertLockHeld(g_msgproc_mutex); - LOCK(cs_main); + LOCK2(::cs_main, m_tx_download_mutex); CTransactionRef porphanTx = nullptr; @@ -4106,7 +4163,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const bool rate_limited = !pfrom.HasPermission(NetPermissionFlags::Addr); uint64_t num_proc = 0; uint64_t num_rate_limit = 0; - Shuffle(vAddr.begin(), vAddr.end(), m_rng); + std::shuffle(vAddr.begin(), vAddr.end(), m_rng); for (CAddress& addr : vAddr) { if (interruptMsgProc) @@ -4173,7 +4230,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const bool reject_tx_invs{RejectIncomingTxs(pfrom)}; - LOCK(cs_main); + LOCK2(cs_main, m_tx_download_mutex); const auto current_time{GetTime<std::chrono::microseconds>()}; uint256* best_block{nullptr}; @@ -4506,7 +4563,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const uint256& hash = peer->m_wtxid_relay ? wtxid : txid; AddKnownTx(*peer, hash); - LOCK(cs_main); + LOCK2(cs_main, m_tx_download_mutex); m_txrequest.ReceivedResponse(pfrom.GetId(), txid); if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid); @@ -4538,8 +4595,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } - if (m_recent_rejects_reconsiderable.contains(wtxid)) { - // When a transaction is already in m_recent_rejects_reconsiderable, we shouldn't submit + if (RecentRejectsReconsiderableFilter().contains(wtxid)) { + // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit // it by itself again. However, look for a matching child in the orphanage, as it is // possible that they succeed as a package. LogPrint(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n", @@ -4551,20 +4608,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, ProcessPackageResult(package_to_validate.value(), package_result); } } - // If a tx is detected by m_recent_rejects it is ignored. Because we haven't + // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't // submitted the tx to our mempool, we won't have computed a DoS // score for it or determined exactly why we consider it invalid. // // This means we won't penalize any peer subsequently relaying a DoSy // tx (even if we penalized the first peer who gave it to us) because - // we have to account for m_recent_rejects showing false positives. In + // we have to account for m_lazy_recent_rejects showing false positives. In // other words, we shouldn't penalize a peer if we aren't *sure* they // submitted a DoSy tx. // - // Note that m_recent_rejects doesn't just record DoSy or invalid + // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid // transactions, but any tx not accepted by the mempool, which may be // due to node policy (vs. consensus). So we can't blanket penalize a - // peer simply for relaying a tx that our m_recent_rejects has caught, + // peer simply for relaying a tx that our m_lazy_recent_rejects has caught, // regardless of false positives. return; } @@ -4591,16 +4648,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, std::sort(unique_parents.begin(), unique_parents.end()); unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end()); - // Distinguish between parents in m_recent_rejects and m_recent_rejects_reconsiderable. - // We can tolerate having up to 1 parent in m_recent_rejects_reconsiderable since we - // submit 1p1c packages. However, fail immediately if any are in m_recent_rejects. + // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable. + // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we + // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects. std::optional<uint256> rejected_parent_reconsiderable; for (const uint256& parent_txid : unique_parents) { - if (m_recent_rejects.contains(parent_txid)) { + if (RecentRejectsFilter().contains(parent_txid)) { fRejectedParents = true; break; - } else if (m_recent_rejects_reconsiderable.contains(parent_txid) && !m_mempool.exists(GenTxid::Txid(parent_txid))) { - // More than 1 parent in m_recent_rejects_reconsiderable: 1p1c will not be + } else if (RecentRejectsReconsiderableFilter().contains(parent_txid) && !m_mempool.exists(GenTxid::Txid(parent_txid))) { + // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be // sufficient to accept this package, so just give up here. if (rejected_parent_reconsiderable.has_value()) { fRejectedParents = true; @@ -4620,7 +4677,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // protocol for getting all unconfirmed parents. const auto gtxid{GenTxid::Txid(parent_txid)}; AddKnownTx(*peer, parent_txid); - // Exclude m_recent_rejects_reconsiderable: the missing parent may have been + // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been // previously rejected for being too low feerate. This orphan might CPFP it. if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) AddTxAnnouncement(pfrom, gtxid, current_time); } @@ -4645,8 +4702,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // regardless of what witness is provided, we will not accept // this, so we don't need to allow for redownload of this txid // from any of our non-wtxidrelay peers. - m_recent_rejects.insert(tx.GetHash().ToUint256()); - m_recent_rejects.insert(tx.GetWitnessHash().ToUint256()); + RecentRejectsFilter().insert(tx.GetHash().ToUint256()); + RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256()); m_txrequest.ForgetTxHash(tx.GetHash()); m_txrequest.ForgetTxHash(tx.GetWitnessHash()); } @@ -5263,7 +5320,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, std::vector<CInv> vInv; vRecv >> vInv; if (vInv.size() <= MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - LOCK(::cs_main); + LOCK(m_tx_download_mutex); for (CInv &inv : vInv) { if (inv.IsGenTxMsg()) { // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as @@ -5321,11 +5378,16 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer) bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc) { + AssertLockNotHeld(m_tx_download_mutex); AssertLockHeld(g_msgproc_mutex); PeerRef peer = GetPeerRef(pfrom->GetId()); if (peer == nullptr) return false; + // For outbound connections, ensure that the initial VERSION message + // has been sent first before processing any incoming messages + if (!pfrom->IsInboundConn() && !peer->m_outbound_version_message_sent) return false; + { LOCK(peer->m_getdata_requests_mutex); if (!peer->m_getdata_requests.empty()) { @@ -5384,6 +5446,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt // by another peer that was already processed; in that case, // the extra work may not be noticed, possibly resulting in an // unnecessary 100ms delay) + LOCK(m_tx_download_mutex); 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()); @@ -5617,7 +5680,7 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic if (pingSend) { uint64_t nonce; do { - nonce = GetRand<uint64_t>(); + nonce = FastRandomContext().rand64(); } while (nonce == 0); peer.m_ping_queued = false; peer.m_ping_start = now; @@ -5654,13 +5717,13 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()}; PushAddress(peer, local_addr); } - peer.m_next_local_addr_send = GetExponentialRand(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); + peer.m_next_local_addr_send = current_time + m_rng.rand_exp_duration(AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } // We sent an `addr` message to this peer recently. Nothing more to do. if (current_time <= peer.m_next_addr_send) return; - peer.m_next_addr_send = GetExponentialRand(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); + peer.m_next_addr_send = current_time + m_rng.rand_exp_duration(AVG_ADDRESS_BROADCAST_INTERVAL); if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) { // Should be impossible since we always check size before adding to @@ -5747,13 +5810,13 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi MakeAndPushMessage(pto, NetMsgType::FEEFILTER, filterToSend); peer.m_fee_filter_sent = filterToSend; } - peer.m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL); + peer.m_next_send_feefilter = current_time + m_rng.rand_exp_duration(AVG_FEEFILTER_BROADCAST_INTERVAL); } // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < peer.m_next_send_feefilter && (currentFilter < 3 * peer.m_fee_filter_sent / 4 || currentFilter > 4 * peer.m_fee_filter_sent / 3)) { - peer.m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY); + peer.m_next_send_feefilter = current_time + m_rng.randrange<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY); } } @@ -5807,6 +5870,7 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer) bool PeerManagerImpl::SendMessages(CNode* pto) { + AssertLockNotHeld(m_tx_download_mutex); AssertLockHeld(g_msgproc_mutex); PeerRef peer = GetPeerRef(pto->GetId()); @@ -5817,6 +5881,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // disconnect misbehaving peers even before the version handshake is complete. if (MaybeDiscourageAndDisconnect(*pto, *peer)) return true; + // Initiate version handshake for outbound connections + if (!pto->IsInboundConn() && !peer->m_outbound_version_message_sent) { + PushNodeVersion(*pto, *peer); + peer->m_outbound_version_message_sent = true; + } + // Don't send anything until the version handshake is complete if (!pto->fSuccessfullyConnected || pto->fDisconnect) return true; @@ -5984,7 +6054,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) CBlock block; const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)}; assert(ret); - CBlockHeaderAndShortTxIDs cmpctblock{block, GetRand<uint64_t>()}; + CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()}; MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock); } state.pindexBestHeaderSent = pBestIndex; @@ -6059,7 +6129,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) if (pto->IsInboundConn()) { tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL); } else { - tx_relay->m_next_inv_send_time = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL); + tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL); } } @@ -6244,10 +6314,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // before the background chainstate to prioritize getting to network tip. FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload, staller); if (m_chainman.BackgroundSyncInProgress() && !IsLimitedPeer(*peer)) { + // If the background tip is not an ancestor of the snapshot block, + // we need to start requesting blocks from their last common ancestor. + const CBlockIndex *from_tip = LastCommonAncestor(m_chainman.GetBackgroundSyncTip(), m_chainman.GetSnapshotBaseBlock()); TryDownloadingHistoricalBlocks( *peer, get_inflight_budget(), - vToDownload, m_chainman.GetBackgroundSyncTip(), + vToDownload, from_tip, Assert(m_chainman.GetSnapshotBaseBlock())); } for (const CBlockIndex *pindex : vToDownload) { @@ -6268,31 +6341,33 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // // Message: getdata (transactions) // - std::vector<std::pair<NodeId, GenTxid>> expired; - auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired); - for (const auto& entry : expired) { - LogPrint(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx", - entry.second.GetHash().ToString(), entry.first); - } - for (const GenTxid& gtxid : requestable) { - // Exclude m_recent_rejects_reconsiderable: we may be requesting a missing parent - // that was previously rejected for being too low feerate. - if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) { - LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", - gtxid.GetHash().ToString(), pto->GetId()); - vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash()); - if (vGetData.size() >= MAX_GETDATA_SZ) { - MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData); - vGetData.clear(); + { + LOCK(m_tx_download_mutex); + std::vector<std::pair<NodeId, GenTxid>> expired; + auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired); + for (const auto& entry : expired) { + LogPrint(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx", + entry.second.GetHash().ToString(), entry.first); + } + for (const GenTxid& gtxid : requestable) { + // Exclude m_lazy_recent_rejects_reconsiderable: we may be requesting a missing parent + // that was previously rejected for being too low feerate. + if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) { + LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", + gtxid.GetHash().ToString(), pto->GetId()); + vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash()); + if (vGetData.size() >= MAX_GETDATA_SZ) { + MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData); + vGetData.clear(); + } + m_txrequest.RequestedTx(pto->GetId(), gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL); + } else { + // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as + // this should already be called whenever a transaction becomes AlreadyHaveTx(). + m_txrequest.ForgetTxHash(gtxid.GetHash()); } - m_txrequest.RequestedTx(pto->GetId(), gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL); - } else { - // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as - // this should already be called whenever a transaction becomes AlreadyHaveTx(). - m_txrequest.ForgetTxHash(gtxid.GetHash()); } - } - + } // release m_tx_download_mutex if (!vGetData.empty()) MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData); diff --git a/src/net_processing.h b/src/net_processing.h index bf9698ee02..a413db98e8 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -76,7 +76,7 @@ public: static std::unique_ptr<PeerManager> make(CConnman& connman, AddrMan& addrman, BanMan* banman, ChainstateManager& chainman, CTxMemPool& pool, node::Warnings& warnings, Options opts); - virtual ~PeerManager() { } + virtual ~PeerManager() = default; /** * Attempt to manually fetch block from a given peer. We must already have the header. diff --git a/src/net_types.h b/src/net_types.h index b9e019d8fd..21ef835b4e 100644 --- a/src/net_types.h +++ b/src/net_types.h @@ -19,7 +19,7 @@ public: int64_t nCreateTime{0}; int64_t nBanUntil{0}; - CBanEntry() {} + CBanEntry() = default; explicit CBanEntry(int64_t nCreateTimeIn) : nCreateTime{nCreateTimeIn} {} diff --git a/src/netaddress.h b/src/netaddress.h index 52fecada1c..24f5c3fb96 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -567,8 +567,8 @@ class CServiceHash { public: CServiceHash() - : m_salt_k0{GetRand<uint64_t>()}, - m_salt_k1{GetRand<uint64_t>()} + : m_salt_k0{FastRandomContext().rand64()}, + m_salt_k1{FastRandomContext().rand64()} { } diff --git a/src/netbase.cpp b/src/netbase.cpp index f5f0997ba6..7193b401bb 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -50,6 +50,7 @@ std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_loo ai_hint.ai_protocol = IPPROTO_TCP; // We don't care which address family (IPv4 or IPv6) is returned ai_hint.ai_family = AF_UNSPEC; + // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only // return addresses whose family we have an address configured for. // @@ -61,7 +62,17 @@ std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_loo addrinfo* ai_res{nullptr}; const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; if (n_err != 0) { - return {}; + if ((ai_hint.ai_flags & AI_ADDRCONFIG) == AI_ADDRCONFIG) { + // AI_ADDRCONFIG on some systems may exclude loopback-only addresses + // If first lookup failed we perform a second lookup without AI_ADDRCONFIG + ai_hint.ai_flags = (ai_hint.ai_flags & ~AI_ADDRCONFIG); + const int n_err_retry{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)}; + if (n_err_retry != 0) { + return {}; + } + } else { + return {}; + } } // Traverse the linked list starting with ai_trav. @@ -445,7 +456,8 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a } if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) { // Failures to connect to a peer that are not proxy errors - LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1])); + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, + "Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1])); return false; } if (pchRet2[2] != 0x00) { // Reserved field must be 0 @@ -573,7 +585,7 @@ static bool ConnectToSocket(const Sock& sock, struct sockaddr* sockaddr, socklen NetworkErrorString(WSAGetLastError())); return false; } else if (occurred == 0) { - LogPrint(BCLog::NET, "connection attempt to %s timed out\n", dest_str); + LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "connection attempt to %s timed out\n", dest_str); return false; } diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp index fa76566652..0fc4e1646a 100644 --- a/src/node/blockmanager_args.cpp +++ b/src/node/blockmanager_args.cpp @@ -16,6 +16,7 @@ namespace node { util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts) { + if (auto value{args.GetBoolArg("-blocksxor")}) opts.use_xor = *value; // 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) { diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index fb62e78138..96cf69927c 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -19,7 +19,7 @@ #include <pow.h> #include <primitives/block.h> #include <primitives/transaction.h> -#include <reverse_iterator.h> +#include <random.h> #include <serialize.h> #include <signet.h> #include <span.h> @@ -37,6 +37,7 @@ #include <validation.h> #include <map> +#include <ranges> #include <unordered_map> namespace kernel { @@ -410,11 +411,11 @@ bool BlockManager::LoadBlockIndex(const std::optional<uint256>& snapshot_blockha m_snapshot_height = au_data.height; CBlockIndex* base{LookupBlockIndex(*snapshot_blockhash)}; - // Since nChainTx (responsible for estimated progress) isn't persisted + // Since m_chain_tx_count (responsible for estimated progress) isn't persisted // to disk, we must bootstrap the value for assumedvalid chainstates // from the hardcoded assumeutxo chainparams. - base->nChainTx = au_data.nChainTx; - LogPrintf("[snapshot] set nChainTx=%d for %s\n", au_data.nChainTx, snapshot_blockhash->ToString()); + base->m_chain_tx_count = au_data.m_chain_tx_count; + LogPrintf("[snapshot] set m_chain_tx_count=%d for %s\n", au_data.m_chain_tx_count, snapshot_blockhash->ToString()); } else { // If this isn't called with a snapshot blockhash, make sure the cached snapshot height // is null. This is relevant during snapshot completion, when the blockman may be loaded @@ -449,15 +450,15 @@ bool BlockManager::LoadBlockIndex(const std::optional<uint256>& snapshot_blockha if (m_snapshot_height && pindex->nHeight == *m_snapshot_height && pindex->GetBlockHash() == *snapshot_blockhash) { // Should have been set above; don't disturb it with code below. - Assert(pindex->nChainTx > 0); - } else if (pindex->pprev->nChainTx > 0) { - pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; + Assert(pindex->m_chain_tx_count > 0); + } else if (pindex->pprev->m_chain_tx_count > 0) { + pindex->m_chain_tx_count = pindex->pprev->m_chain_tx_count + pindex->nTx; } else { - pindex->nChainTx = 0; + pindex->m_chain_tx_count = 0; m_blocks_unlinked.insert(std::make_pair(pindex->pprev, pindex)); } } else { - pindex->nChainTx = pindex->nTx; + pindex->m_chain_tx_count = pindex->nTx; } } if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) { @@ -578,7 +579,7 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) { const MapCheckpoints& checkpoints = data.mapCheckpoints; - for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) { + for (const MapCheckpoints::value_type& i : checkpoints | std::views::reverse) { const uint256& hash = i.second; const CBlockIndex* pindex = LookupBlockIndex(hash); if (pindex) { @@ -588,18 +589,18 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) return nullptr; } -bool BlockManager::IsBlockPruned(const CBlockIndex& block) +bool BlockManager::IsBlockPruned(const CBlockIndex& block) const { AssertLockHeld(::cs_main); return m_have_pruned && !(block.nStatus & BLOCK_HAVE_DATA) && (block.nTx > 0); } -const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& upper_block, const CBlockIndex* lower_block) +const CBlockIndex* BlockManager::GetFirstBlock(const CBlockIndex& upper_block, uint32_t status_mask, const CBlockIndex* lower_block) const { AssertLockHeld(::cs_main); const CBlockIndex* last_block = &upper_block; - assert(last_block->nStatus & BLOCK_HAVE_DATA); // 'upper_block' must have data - while (last_block->pprev && (last_block->pprev->nStatus & BLOCK_HAVE_DATA)) { + assert((last_block->nStatus & status_mask) == status_mask); // 'upper_block' must satisfy the status mask + while (last_block->pprev && ((last_block->pprev->nStatus & status_mask) == status_mask)) { if (lower_block) { // Return if we reached the lower_block if (last_block == lower_block) return lower_block; @@ -616,7 +617,7 @@ const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& upper_bl bool BlockManager::CheckBlockDataAvailability(const CBlockIndex& upper_block, const CBlockIndex& lower_block) { if (!(upper_block.nStatus & BLOCK_HAVE_DATA)) return false; - return GetFirstStoredBlock(upper_block, &lower_block) == &lower_block; + return GetFirstBlock(upper_block, BLOCK_HAVE_DATA, &lower_block) == &lower_block; } // If we're using -prune with -reindex, then delete block files that will be ignored by the @@ -703,15 +704,10 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in { const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())}; - if (pos.IsNull()) { - LogError("%s: no undo data available\n", __func__); - return false; - } - // Open history file to read AutoFile filein{OpenUndoFile(pos, true)}; if (filein.IsNull()) { - LogError("%s: OpenUndoFile failed\n", __func__); + LogError("%s: OpenUndoFile failed for %s\n", __func__, pos.ToString()); return false; } @@ -723,13 +719,13 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in verifier >> blockundo; filein >> hashChecksum; } catch (const std::exception& e) { - LogError("%s: Deserialize or I/O error - %s\n", __func__, e.what()); + LogError("%s: Deserialize or I/O error - %s at %s\n", __func__, e.what(), pos.ToString()); return false; } // Verify checksum if (hashChecksum != verifier.GetHash()) { - LogError("%s: Checksum mismatch\n", __func__); + LogError("%s: Checksum mismatch at %s\n", __func__, pos.ToString()); return false; } @@ -739,7 +735,7 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in bool BlockManager::FlushUndoFile(int block_file, bool finalize) { FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize); - if (!UndoFileSeq().Flush(undo_pos_old, finalize)) { + if (!m_undo_file_seq.Flush(undo_pos_old, finalize)) { m_opts.notifications.flushError(_("Flushing undo file to disk failed. This is likely the result of an I/O error.")); return false; } @@ -761,7 +757,7 @@ bool BlockManager::FlushBlockFile(int blockfile_num, bool fFinalize, bool finali assert(static_cast<int>(m_blockfile_info.size()) > blockfile_num); FlatFilePos block_pos_old(blockfile_num, m_blockfile_info[blockfile_num].nSize); - if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) { + if (!m_block_file_seq.Flush(block_pos_old, fFinalize)) { m_opts.notifications.flushError(_("Flushing block file to disk failed. This is likely the result of an I/O error.")); success = false; } @@ -813,38 +809,28 @@ void BlockManager::UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const std::error_code ec; for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) { FlatFilePos pos(*it, 0); - const bool removed_blockfile{fs::remove(BlockFileSeq().FileName(pos), ec)}; - const bool removed_undofile{fs::remove(UndoFileSeq().FileName(pos), ec)}; + const bool removed_blockfile{fs::remove(m_block_file_seq.FileName(pos), ec)}; + const bool removed_undofile{fs::remove(m_undo_file_seq.FileName(pos), ec)}; if (removed_blockfile || removed_undofile) { LogPrint(BCLog::BLOCKSTORAGE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it); } } } -FlatFileSeq BlockManager::BlockFileSeq() const -{ - return FlatFileSeq(m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE); -} - -FlatFileSeq BlockManager::UndoFileSeq() const -{ - return FlatFileSeq(m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE); -} - AutoFile BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const { - return AutoFile{BlockFileSeq().Open(pos, fReadOnly)}; + return AutoFile{m_block_file_seq.Open(pos, fReadOnly), m_xor_key}; } /** Open an undo file (rev?????.dat) */ AutoFile BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const { - return AutoFile{UndoFileSeq().Open(pos, fReadOnly)}; + return AutoFile{m_undo_file_seq.Open(pos, fReadOnly), m_xor_key}; } fs::path BlockManager::GetBlockPosFilename(const FlatFilePos& pos) const { - return BlockFileSeq().FileName(pos); + return m_block_file_seq.FileName(pos); } FlatFilePos BlockManager::FindNextBlockPos(unsigned int nAddSize, unsigned int nHeight, uint64_t nTime) @@ -924,7 +910,7 @@ FlatFilePos BlockManager::FindNextBlockPos(unsigned int nAddSize, unsigned int n m_blockfile_info[nFile].nSize += nAddSize; bool out_of_space; - size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space); + size_t bytes_allocated = m_block_file_seq.Allocate(pos, nAddSize, out_of_space); if (out_of_space) { m_opts.notifications.fatalError(_("Disk space is too low!")); return {}; @@ -970,7 +956,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP m_dirty_fileinfo.insert(nFile); bool out_of_space; - size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space); + size_t bytes_allocated = m_undo_file_seq.Allocate(pos, nAddSize, out_of_space); if (out_of_space) { return FatalError(m_opts.notifications, state, _("Disk space is too low!")); } @@ -986,7 +972,7 @@ bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const // Open history file to append AutoFile fileout{OpenBlockFile(pos)}; if (fileout.IsNull()) { - LogError("WriteBlockToDisk: OpenBlockFile failed\n"); + LogError("%s: OpenBlockFile failed\n", __func__); return false; } @@ -997,7 +983,7 @@ bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const // Write block long fileOutPos = ftell(fileout.Get()); if (fileOutPos < 0) { - LogError("WriteBlockToDisk: ftell failed\n"); + LogError("%s: ftell failed\n", __func__); return false; } pos.nPos = (unsigned int)fileOutPos; @@ -1016,7 +1002,7 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid if (block.GetUndoPos().IsNull()) { FlatFilePos _pos; if (!FindUndoPos(state, block.nFile, _pos, ::GetSerializeSize(blockundo) + 40)) { - LogError("ConnectBlock(): FindUndoPos failed\n"); + LogError("%s: FindUndoPos failed\n", __func__); return false; } if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash())) { @@ -1055,7 +1041,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons // Open history file to read AutoFile filein{OpenBlockFile(pos, true)}; if (filein.IsNull()) { - LogError("ReadBlockFromDisk: OpenBlockFile failed for %s\n", pos.ToString()); + LogError("%s: OpenBlockFile failed for %s\n", __func__, pos.ToString()); return false; } @@ -1069,13 +1055,13 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons // Check the header if (!CheckProofOfWork(block.GetHash(), block.nBits, GetConsensus())) { - LogError("ReadBlockFromDisk: Errors in block header at %s\n", pos.ToString()); + LogError("%s: Errors in block header at %s\n", __func__, pos.ToString()); return false; } // Signet only: check block solution if (GetConsensus().signet_blocks && !CheckSignetBlockSolution(block, GetConsensus())) { - LogError("ReadBlockFromDisk: Errors in block solution at %s\n", pos.ToString()); + LogError("%s: Errors in block solution at %s\n", __func__, pos.ToString()); return false; } @@ -1090,8 +1076,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) co return false; } if (block.GetHash() != index.GetBlockHash()) { - LogError("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s\n", - index.ToString(), block_pos.ToString()); + LogError("%s: GetHash() doesn't match index for %s at %s\n", __func__, index.ToString(), block_pos.ToString()); return false; } return true; @@ -1160,6 +1145,54 @@ FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight) return blockPos; } +static auto InitBlocksdirXorKey(const BlockManager::Options& opts) +{ + // Bytes are serialized without length indicator, so this is also the exact + // size of the XOR-key file. + std::array<std::byte, 8> xor_key{}; + + if (opts.use_xor && fs::is_empty(opts.blocks_dir)) { + // Only use random fresh key when the boolean option is set and on the + // very first start of the program. + FastRandomContext{}.fillrand(xor_key); + } + + const fs::path xor_key_path{opts.blocks_dir / "xor.dat"}; + if (fs::exists(xor_key_path)) { + // A pre-existing xor key file has priority. + AutoFile xor_key_file{fsbridge::fopen(xor_key_path, "rb")}; + xor_key_file >> xor_key; + } else { + // Create initial or missing xor key file + AutoFile xor_key_file{fsbridge::fopen(xor_key_path, +#ifdef __MINGW64__ + "wb" // Temporary workaround for https://github.com/bitcoin/bitcoin/issues/30210 +#else + "wbx" +#endif + )}; + xor_key_file << xor_key; + } + // If the user disabled the key, it must be zero. + if (!opts.use_xor && xor_key != decltype(xor_key){}) { + throw std::runtime_error{ + strprintf("The blocksdir XOR-key can not be disabled when a random key was already stored! " + "Stored key: '%s', stored path: '%s'.", + HexStr(xor_key), fs::PathToString(xor_key_path)), + }; + } + LogInfo("Using obfuscation key for blocksdir *.dat files (%s): '%s'\n", fs::PathToString(opts.blocks_dir), HexStr(xor_key)); + return std::vector<std::byte>{xor_key.begin(), xor_key.end()}; +} + +BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts) + : m_prune_mode{opts.prune_target > 0}, + m_xor_key{InitBlocksdirXorKey(opts)}, + m_opts{std::move(opts)}, + m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}}, + m_undo_file_seq{FlatFileSeq{m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE}}, + m_interrupt{interrupt} {} + class ImportingNow { std::atomic<bool>& m_importing; diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 108a08a72b..821bbf5109 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -166,9 +166,6 @@ private: [[nodiscard]] bool FlushChainstateBlockFile(int tip_height); bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize); - FlatFileSeq BlockFileSeq() const; - FlatFileSeq UndoFileSeq() const; - AutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const; /** @@ -243,6 +240,8 @@ private: const bool m_prune_mode; + const std::vector<std::byte> m_xor_key; + /** Dirty block index entries. */ std::set<CBlockIndex*> m_dirty_blockindex; @@ -261,13 +260,13 @@ private: const kernel::BlockManagerOpts m_opts; + const FlatFileSeq m_block_file_seq; + const FlatFileSeq m_undo_file_seq; + public: using Options = kernel::BlockManagerOpts; - explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts) - : m_prune_mode{opts.prune_target > 0}, - m_opts{std::move(opts)}, - m_interrupt{interrupt} {} + explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts); const util::SignalInterrupt& m_interrupt; std::atomic<bool> m_importing{false}; @@ -372,16 +371,39 @@ public: //! (part of the same chain). bool CheckBlockDataAvailability(const CBlockIndex& upper_block LIFETIMEBOUND, const CBlockIndex& lower_block LIFETIMEBOUND) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - //! Find the first stored ancestor of start_block immediately after the last - //! pruned ancestor. Return value will never be null. Caller is responsible - //! for ensuring that start_block has data is not pruned. - const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block LIFETIMEBOUND, const CBlockIndex* lower_block=nullptr) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + /** + * @brief Returns the earliest block with specified `status_mask` flags set after + * the latest block _not_ having those flags. + * + * This function starts from `upper_block`, which must have all + * `status_mask` flags set, and iterates backwards through its ancestors. It + * continues as long as each block has all `status_mask` flags set, until + * reaching the oldest ancestor or `lower_block`. + * + * @pre `upper_block` must have all `status_mask` flags set. + * @pre `lower_block` must be null or an ancestor of `upper_block` + * + * @param upper_block The starting block for the search, which must have all + * `status_mask` flags set. + * @param status_mask Bitmask specifying required status flags. + * @param lower_block The earliest possible block to return. If null, the + * search can extend to the genesis block. + * + * @return A non-null pointer to the earliest block between `upper_block` + * and `lower_block`, inclusive, such that every block between the + * returned block and `upper_block` has `status_mask` flags set. + */ + const CBlockIndex* GetFirstBlock( + const CBlockIndex& upper_block LIFETIMEBOUND, + uint32_t status_mask, + const CBlockIndex* lower_block = nullptr + ) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** True if any block files have ever been pruned. */ bool m_have_pruned = false; //! Check whether the block associated with this index entry is pruned or not. - bool IsBlockPruned(const CBlockIndex& block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool IsBlockPruned(const CBlockIndex& block) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); //! Create or update a prune lock identified by its name void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp index bc4a815a3e..39b5f3ad3e 100644 --- a/src/node/chainstatemanager_args.cpp +++ b/src/node/chainstatemanager_args.cpp @@ -56,6 +56,16 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManage opts.worker_threads_num = std::clamp(script_threads - 1, 0, MAX_SCRIPTCHECK_THREADS); LogPrintf("Script verification uses %d additional threads\n", opts.worker_threads_num); + if (auto max_size = args.GetIntArg("-maxsigcachesize")) { + // 1. When supplied with a max_size of 0, both the signature cache and + // script execution cache create the minimum possible cache (2 + // elements). Therefore, we can use 0 as a floor here. + // 2. Multiply first, divide after to avoid integer truncation. + size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2; + opts.script_execution_cache_bytes = clamped_size_each; + opts.signature_cache_bytes = clamped_size_each; + } + return {}; } } // namespace node diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h index 22c241cb78..85c34f5834 100644 --- a/src/node/interface_ui.h +++ b/src/node/interface_ui.h @@ -6,9 +6,10 @@ #ifndef BITCOIN_NODE_INTERFACE_UI_H #define BITCOIN_NODE_INTERFACE_UI_H +#include <cstdint> #include <functional> -#include <memory> #include <string> +#include <vector> class CBlockIndex; enum class SynchronizationState; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index fa151407fa..9fe08eb3dd 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -278,6 +278,7 @@ public: int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } + size_t getMempoolMaxUsage() override { return m_context->mempool ? m_context->mempool->m_opts.max_size_bytes : 0; } bool getHeaderTip(int& height, int64_t& block_time) override { LOCK(::cs_main); @@ -289,6 +290,13 @@ public: } return false; } + std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() override + { + if (m_context->connman) + return m_context->connman->getNetLocalAddresses(); + else + return {}; + } int getNumBlocks() override { LOCK(::cs_main); @@ -883,12 +891,11 @@ public: return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); } - std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override + std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override { - BlockAssembler::Options options; - ApplyArgsManOptions(gArgs, options); - - return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key); + BlockAssembler::Options assemble_options{options}; + ApplyArgsManOptions(*Assert(m_node.args), assemble_options); + return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key); } NodeContext* context() override { return &m_node; } diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index f329affb1d..a488c1b149 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -93,6 +93,9 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP } mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf); + if (!mempool_opts.full_rbf) { + LogInfo("Warning: mempoolfullrbf=0 set but deprecated and will be removed in a future release\n"); + } mempool_opts.persist_v1_dat = argsman.GetBoolArg("-persistmempoolv1", mempool_opts.persist_v1_dat); diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 291f1d5fc7..fa2d979b86 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -59,14 +59,17 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman) static BlockAssembler::Options ClampOptions(BlockAssembler::Options options) { - // 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); + Assert(options.coinbase_max_additional_weight <= DEFAULT_BLOCK_MAX_WEIGHT); + Assert(options.coinbase_output_max_additional_sigops <= MAX_BLOCK_SIGOPS_COST); + // Limit weight to between coinbase_max_additional_weight and DEFAULT_BLOCK_MAX_WEIGHT for sanity: + // Coinbase (reserved) outputs can safely exceed -blockmaxweight, but the rest of the block template will be empty. + options.nBlockMaxWeight = std::clamp<size_t>(options.nBlockMaxWeight, options.coinbase_max_additional_weight, 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_mempool{options.use_mempool ? mempool : nullptr}, m_chainstate{chainstate}, m_options{ClampOptions(options)} { @@ -87,8 +90,8 @@ void BlockAssembler::resetBlock() inBlock.clear(); // Reserve space for coinbase tx - nBlockWeight = 4000; - nBlockSigOpsCost = 400; + nBlockWeight = m_options.coinbase_max_additional_weight; + nBlockSigOpsCost = m_options.coinbase_output_max_additional_sigops; // These counters do not include coinbase tx nBlockTx = 0; @@ -379,7 +382,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele ++nConsecutiveFailed; if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight > - m_options.nBlockMaxWeight - 4000) { + m_options.nBlockMaxWeight - m_options.coinbase_max_additional_weight) { // Give up if we're close to full and haven't succeeded in a while break; } diff --git a/src/node/miner.h b/src/node/miner.h index 622ca16c8f..1b82943766 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_NODE_MINER_H #define BITCOIN_NODE_MINER_H +#include <node/types.h> #include <policy/policy.h> #include <primitives/block.h> #include <txmempool.h> @@ -96,21 +97,25 @@ struct CompareTxIterByAncestorCount { } }; + +struct CTxMemPoolModifiedEntry_Indices final : boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + modifiedentry_iter, + CompareCTxMemPoolIter + >, + // sorted by modified ancestor fee rate + boost::multi_index::ordered_non_unique< + // Reuse same tag from CTxMemPool's similar index + boost::multi_index::tag<ancestor_score>, + boost::multi_index::identity<CTxMemPoolModifiedEntry>, + CompareTxMemPoolEntryByAncestorFee + > +> +{}; + typedef boost::multi_index_container< CTxMemPoolModifiedEntry, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - modifiedentry_iter, - CompareCTxMemPoolIter - >, - // sorted by modified ancestor fee rate - boost::multi_index::ordered_non_unique< - // Reuse same tag from CTxMemPool's similar index - boost::multi_index::tag<ancestor_score>, - boost::multi_index::identity<CTxMemPoolModifiedEntry>, - CompareTxMemPoolEntryByAncestorFee - > - > + CTxMemPoolModifiedEntry_Indices > indexed_modified_transaction_set; typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter; @@ -153,7 +158,7 @@ private: Chainstate& m_chainstate; public: - struct Options { + struct Options : BlockCreateOptions { // Configuration parameters for the block size size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT}; CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE}; diff --git a/src/node/mini_miner.cpp b/src/node/mini_miner.cpp index 58422c4439..d7d15554b3 100644 --- a/src/node/mini_miner.cpp +++ b/src/node/mini_miner.cpp @@ -174,7 +174,7 @@ MiniMiner::MiniMiner(const std::vector<MiniMinerMempoolEntry>& manual_entries, SanityCheck(); } -// Compare by min(ancestor feerate, individual feerate), then iterator +// Compare by min(ancestor feerate, individual feerate), then txid // // Under the ancestor-based mining approach, high-feerate children can pay for parents, but high-feerate // parents do not incentive inclusion of their children. Therefore the mining algorithm only considers @@ -183,21 +183,13 @@ struct AncestorFeerateComparator { template<typename I> bool operator()(const I& a, const I& b) const { - auto min_feerate = [](const MiniMinerMempoolEntry& e) -> CFeeRate { - const CAmount ancestor_fee{e.GetModFeesWithAncestors()}; - const int64_t ancestor_size{e.GetSizeWithAncestors()}; - const CAmount tx_fee{e.GetModifiedFee()}; - const int64_t tx_size{e.GetTxSize()}; - // Comparing ancestor feerate with individual feerate: - // ancestor_fee / ancestor_size <= tx_fee / tx_size - // Avoid division and possible loss of precision by - // multiplying both sides by the sizes: - return ancestor_fee * tx_size < tx_fee * ancestor_size ? - CFeeRate(ancestor_fee, ancestor_size) : - CFeeRate(tx_fee, tx_size); + auto min_feerate = [](const MiniMinerMempoolEntry& e) -> FeeFrac { + FeeFrac self_feerate(e.GetModifiedFee(), e.GetTxSize()); + FeeFrac ancestor_feerate(e.GetModFeesWithAncestors(), e.GetSizeWithAncestors()); + return std::min(ancestor_feerate, self_feerate); }; - CFeeRate a_feerate{min_feerate(a->second)}; - CFeeRate b_feerate{min_feerate(b->second)}; + FeeFrac a_feerate{min_feerate(a->second)}; + FeeFrac b_feerate{min_feerate(b->second)}; if (a_feerate != b_feerate) { return a_feerate > b_feerate; } diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 591dcd698d..0f45da45db 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -55,7 +55,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t const Coin& existingCoin = view.AccessCoin(COutPoint(txid, o)); // IsSpent doesn't mean the coin is spent, it means the output doesn't exist. // So if the output does exist, then this transaction exists in the chain. - if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN; + if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_UTXO_SET; } if (auto mempool_tx = node.mempool->get(txid); mempool_tx) { diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp index d62046daaa..e6e19c5756 100644 --- a/src/node/txreconciliation.cpp +++ b/src/node/txreconciliation.cpp @@ -85,7 +85,7 @@ public: 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)}; + const uint64_t local_salt{FastRandomContext().rand64()}; // 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. diff --git a/src/node/types.h b/src/node/types.h index 0461e85f43..1302f1b127 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -13,17 +13,37 @@ #ifndef BITCOIN_NODE_TYPES_H #define BITCOIN_NODE_TYPES_H +#include <cstddef> + namespace node { enum class TransactionError { OK, //!< No error MISSING_INPUTS, - ALREADY_IN_CHAIN, + ALREADY_IN_UTXO_SET, MEMPOOL_REJECTED, MEMPOOL_ERROR, MAX_FEE_EXCEEDED, MAX_BURN_EXCEEDED, INVALID_PACKAGE, }; + +struct BlockCreateOptions { + /** + * Set false to omit mempool transactions + */ + bool use_mempool{true}; + /** + * The maximum additional weight which the pool will add to the coinbase + * scriptSig, witness and outputs. This must include any additional + * weight needed for larger CompactSize encoded lengths. + */ + size_t coinbase_max_additional_weight{4000}; + /** + * The maximum additional sigops which the pool will add in coinbase + * transaction outputs. + */ + size_t coinbase_output_max_additional_sigops{400}; +}; } // namespace node #endif // BITCOIN_NODE_TYPES_H diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index a7c4135787..e4eb6d60ad 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -28,16 +28,17 @@ class Chainstate; namespace node { //! Metadata describing a serialized version of a UTXO set from which an //! assumeutxo Chainstate can be constructed. +//! All metadata fields come from an untrusted file, so must be validated +//! before being used. Thus, new fields should be added only if needed. class SnapshotMetadata { - const uint16_t m_version{1}; - const std::set<uint16_t> m_supported_versions{1}; + inline static const uint16_t VERSION{2}; + const std::set<uint16_t> m_supported_versions{VERSION}; const MessageStartChars m_network_magic; public: //! The hash of the block that reflects the tip of the chain for the //! UTXO set contained in this snapshot. uint256 m_base_blockhash; - uint32_t m_base_blockheight; //! The number of coins in the UTXO set contained in this snapshot. Used @@ -50,19 +51,16 @@ public: SnapshotMetadata( const MessageStartChars network_magic, const uint256& base_blockhash, - const int base_blockheight, uint64_t coins_count) : m_network_magic(network_magic), m_base_blockhash(base_blockhash), - m_base_blockheight(base_blockheight), m_coins_count(coins_count) { } template <typename Stream> inline void Serialize(Stream& s) const { s << SNAPSHOT_MAGIC_BYTES; - s << m_version; + s << VERSION; s << m_network_magic; - s << m_base_blockheight; s << m_base_blockhash; s << m_coins_count; } @@ -98,7 +96,6 @@ public: } } - s >> m_base_blockheight; s >> m_base_blockhash; s >> m_coins_count; } diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp deleted file mode 100644 index ddf24f798d..0000000000 --- a/src/node/validation_cache_args.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// 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/validation_cache_args.h> - -#include <kernel/validation_cache_sizes.h> - -#include <common/args.h> - -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <memory> -#include <optional> - -using kernel::ValidationCacheSizes; - -namespace node { -void ApplyArgsManOptions(const ArgsManager& argsman, ValidationCacheSizes& cache_sizes) -{ - if (auto max_size = argsman.GetIntArg("-maxsigcachesize")) { - // 1. When supplied with a max_size of 0, both InitSignatureCache and - // InitScriptExecutionCache create the minimum possible cache (2 - // elements). Therefore, we can use 0 as a floor here. - // 2. Multiply first, divide after to avoid integer truncation. - size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2; - cache_sizes = { - .signature_cache_bytes = clamped_size_each, - .script_execution_cache_bytes = clamped_size_each, - }; - } -} -} // namespace node diff --git a/src/node/validation_cache_args.h b/src/node/validation_cache_args.h deleted file mode 100644 index f447c13b49..0000000000 --- a/src/node/validation_cache_args.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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_VALIDATION_CACHE_ARGS_H -#define BITCOIN_NODE_VALIDATION_CACHE_ARGS_H - -class ArgsManager; -namespace kernel { -struct ValidationCacheSizes; -}; - -namespace node { -void ApplyArgsManOptions(const ArgsManager& argsman, kernel::ValidationCacheSizes& cache_sizes); -} // namespace node - -#endif // BITCOIN_NODE_VALIDATION_CACHE_ARGS_H diff --git a/src/node/warnings.cpp b/src/node/warnings.cpp index b99c845900..87389e472b 100644 --- a/src/node/warnings.cpp +++ b/src/node/warnings.cpp @@ -28,8 +28,7 @@ Warnings::Warnings() } bool Warnings::Set(warning_type id, bilingual_str message) { - LOCK(m_mutex); - const auto& [_, inserted]{m_warnings.insert({id, std::move(message)})}; + const auto& [_, inserted]{WITH_LOCK(m_mutex, return m_warnings.insert({id, std::move(message)}))}; if (inserted) uiInterface.NotifyAlertChanged(); return inserted; } diff --git a/src/policy/feerate.h b/src/policy/feerate.h index 2e50172914..d742a43acc 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -38,10 +38,8 @@ private: public: /** Fee rate of 0 satoshis per kvB */ CFeeRate() : nSatoshisPerK(0) { } - template<typename I> + template<std::integral I> // Disallow silent float -> int conversion explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { - // We've previously had bugs creep in from silent double->int conversion... - static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats"); } /** diff --git a/src/policy/fees.h b/src/policy/fees.h index f34f66d3f0..a95cc19dd4 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -283,7 +283,7 @@ private: { unsigned int blockHeight{0}; unsigned int bucketIndex{0}; - TxStatsInfo() {} + TxStatsInfo() = default; }; // map of txids to information about that transaction diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index e84a8428bf..68d879b5b8 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -225,6 +225,11 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // get the scriptPubKey corresponding to this input: CScript prevScript = prev.scriptPubKey; + // witness stuffing detected + if (prevScript.IsPayToAnchor()) { + return false; + } + bool p2sh = false; if (prevScript.IsPayToScriptHash()) { std::vector <std::vector<unsigned char> > stack; diff --git a/src/pow.cpp b/src/pow.cpp index 1e8d53de8b..50de8946be 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -61,7 +61,19 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF // Retarget const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); arith_uint256 bnNew; - bnNew.SetCompact(pindexLast->nBits); + + // Special difficulty rule for Testnet4 + if (params.enforce_BIP94) { + // Here we use the first block of the difficulty period. This way + // the real difficulty is always preserved in the first block as + // it is not allowed to use the min-difficulty exception. + int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1); + const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst); + bnNew.SetCompact(pindexFirst->nBits); + } else { + bnNew.SetCompact(pindexLast->nBits); + } + bnNew *= nActualTimespan; bnNew /= params.nPowTargetTimespan; diff --git a/src/prevector.h b/src/prevector.h index 4776db789b..6dcc305268 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -242,7 +242,7 @@ public: fill(item_ptr(0), first, last); } - prevector() {} + prevector() = default; explicit prevector(size_type n) { resize(n); diff --git a/src/primitives/block.h b/src/primitives/block.h index 832f8a03f7..207d2b2980 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -133,7 +133,7 @@ struct CBlockLocator std::vector<uint256> vHave; - CBlockLocator() {} + CBlockLocator() = default; explicit CBlockLocator(std::vector<uint256>&& have) : vHave(std::move(have)) {} diff --git a/src/psbt.h b/src/psbt.h index 4607304046..6d49864b3c 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -225,7 +225,7 @@ struct PSBTInput void FillSignatureData(SignatureData& sigdata) const; void FromSignatureData(const SignatureData& sigdata); void Merge(const PSBTInput& input); - PSBTInput() {} + PSBTInput() = default; template <typename Stream> inline void Serialize(Stream& s) const { @@ -726,7 +726,7 @@ struct PSBTOutput void FillSignatureData(SignatureData& sigdata) const; void FromSignatureData(const SignatureData& sigdata); void Merge(const PSBTOutput& output); - PSBTOutput() {} + PSBTOutput() = default; template <typename Stream> inline void Serialize(Stream& s) const { @@ -967,7 +967,7 @@ struct PartiallySignedTransaction [[nodiscard]] bool Merge(const PartiallySignedTransaction& psbt); bool AddInput(const CTxIn& txin, PSBTInput& psbtin); bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout); - PartiallySignedTransaction() {} + PartiallySignedTransaction() = default; explicit PartiallySignedTransaction(const CMutableTransaction& tx); /** * Finds the UTXO for a given input index @@ -1177,8 +1177,13 @@ struct PartiallySignedTransaction inputs.push_back(input); // Make sure the non-witness utxo matches the outpoint - if (input.non_witness_utxo && input.non_witness_utxo->GetHash() != tx->vin[i].prevout.hash) { - throw std::ios_base::failure("Non-witness UTXO does not match outpoint hash"); + if (input.non_witness_utxo) { + if (input.non_witness_utxo->GetHash() != tx->vin[i].prevout.hash) { + throw std::ios_base::failure("Non-witness UTXO does not match outpoint hash"); + } + if (tx->vin[i].prevout.n >= input.non_witness_utxo->vout.size()) { + throw std::ios_base::failure("Input specifies output index that does not exist"); + } } ++i; } diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 70ed40b2a1..b0bc1f4806 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -44,6 +44,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri ui->passEdit1->hide(); setWindowTitle(tr("Encrypt wallet")); break; + case UnlockMigration: case Unlock: // Ask passphrase ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); ui->passLabel2->hide(); @@ -80,7 +81,7 @@ void AskPassphraseDialog::setModel(WalletModel *_model) void AskPassphraseDialog::accept() { SecureString oldpass, newpass1, newpass2; - if (!model && mode != Encrypt) + if (!model && mode != Encrypt && mode != UnlockMigration) return; oldpass.reserve(MAX_PASSPHRASE_SIZE); newpass1.reserve(MAX_PASSPHRASE_SIZE); @@ -181,6 +182,10 @@ void AskPassphraseDialog::accept() QMessageBox::critical(this, tr("Wallet unlock failed"), e.what()); } break; + case UnlockMigration: + Assume(m_passphrase_out)->assign(oldpass); + QDialog::accept(); + break; case ChangePass: if(newpass1 == newpass2) { @@ -224,6 +229,7 @@ void AskPassphraseDialog::textChanged() case Encrypt: // New passphrase x2 acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); break; + case UnlockMigration: case Unlock: // Old passphrase x1 acceptable = !ui->passEdit1->text().isEmpty(); break; diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 370ea1de7e..c567c29428 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -26,6 +26,7 @@ public: Encrypt, /**< Ask passphrase twice and encrypt */ Unlock, /**< Ask passphrase and unlock */ ChangePass, /**< Ask old passphrase + new passphrase twice */ + UnlockMigration, /**< Ask passphrase for unlocking during migration */ }; explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 6c5725533b..690c2b6f5a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -60,7 +60,7 @@ #include <QTranslator> #include <QWindow> -#if defined(QT_STATICPLUGIN) +#if defined(QT_STATIC) #include <QtPlugin> #if defined(QT_QPA_PLATFORM_XCB) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a43009d954..6d66c7473b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -360,6 +360,7 @@ void BitcoinGUI::createActions() m_migrate_wallet_action = new QAction(tr("Migrate Wallet"), this); m_migrate_wallet_action->setEnabled(false); m_migrate_wallet_action->setStatusTip(tr("Migrate a wallet")); + m_migrate_wallet_menu = new QMenu(this); showHelpMessageAction = new QAction(tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); @@ -396,16 +397,15 @@ void BitcoinGUI::createActions() connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked); connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] { m_open_wallet_menu->clear(); - for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) { - const std::string& path = i.first; - QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); - // Menu items remove single &. Single & are shown when && is in - // the string, but only the first occurrence. So replace only - // the first & with &&. - name.replace(name.indexOf(QChar('&')), 1, QString("&&")); + for (const auto& [path, info] : m_wallet_controller->listWalletDir()) { + const auto& [loaded, _] = info; + QString name = GUIUtil::WalletDisplayName(path); + // An single ampersand in the menu item's text sets a shortcut for this item. + // Single & are shown when && is in the string. So replace & with &&. + name.replace(QChar('&'), QString("&&")); QAction* action = m_open_wallet_menu->addAction(name); - if (i.second) { + if (loaded) { // This wallet is already loaded action->setEnabled(false); continue; @@ -456,10 +456,31 @@ void BitcoinGUI::createActions() connect(m_close_all_wallets_action, &QAction::triggered, [this] { m_wallet_controller->closeAllWallets(this); }); - connect(m_migrate_wallet_action, &QAction::triggered, [this] { - auto activity = new MigrateWalletActivity(m_wallet_controller, this); - connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet); - activity->migrate(walletFrame->currentWalletModel()); + connect(m_migrate_wallet_menu, &QMenu::aboutToShow, [this] { + m_migrate_wallet_menu->clear(); + for (const auto& [wallet_name, info] : m_wallet_controller->listWalletDir()) { + const auto& [loaded, format] = info; + + if (format != "bdb") { // Skip already migrated wallets + continue; + } + + QString name = GUIUtil::WalletDisplayName(wallet_name); + // An single ampersand in the menu item's text sets a shortcut for this item. + // Single & are shown when && is in the string. So replace & with &&. + name.replace(QChar('&'), QString("&&")); + QAction* action = m_migrate_wallet_menu->addAction(name); + + connect(action, &QAction::triggered, [this, wallet_name] { + auto activity = new MigrateWalletActivity(m_wallet_controller, this); + connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet); + activity->migrate(wallet_name); + }); + } + if (m_migrate_wallet_menu->isEmpty()) { + QAction* action = m_migrate_wallet_menu->addAction(tr("No wallets available")); + action->setEnabled(false); + } }); connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy); connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction); @@ -692,6 +713,8 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller, bool s m_open_wallet_action->setEnabled(true); m_open_wallet_action->setMenu(m_open_wallet_menu); m_restore_wallet_action->setEnabled(true); + m_migrate_wallet_action->setEnabled(true); + m_migrate_wallet_action->setMenu(m_migrate_wallet_menu); GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); @@ -772,7 +795,6 @@ void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model) } } updateWindowTitle(); - m_migrate_wallet_action->setEnabled(wallet_model->wallet().isLegacy()); } void BitcoinGUI::setCurrentWalletBySelectorIndex(int index) @@ -806,7 +828,6 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) openAction->setEnabled(enabled); m_close_wallet_action->setEnabled(enabled); m_close_all_wallets_action->setEnabled(enabled); - m_migrate_wallet_action->setEnabled(enabled); } void BitcoinGUI::createTrayIcon() diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 6035647f1c..13773831a0 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -87,6 +87,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous " "cluster of unconfirmed transactions."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Failed to remove snapshot chainstate dir (%s). Manually remove it before " +"restarting.\n"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Failed to rename invalid peers.dat file. Please move or delete it and try " "again."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -96,6 +99,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "File %s already exists. If you are sure this is what you want, move it out " "of the way first."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Flushing block file to disk failed. This is likely the result of an I/O " +"error."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Flushing undo file to disk failed. This is likely the result of an I/O error."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet " "forbids connections to IPv4/IPv6"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -106,6 +114,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "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."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Maximum transaction weight is less than transaction weight without inputs"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Maximum transaction weight is too low, can not accommodate change output"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "More than one onion bind address is provided. Using %s for the automatically " "created Tor onion service."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -130,9 +142,6 @@ 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", "" "Please contribute if you find %s useful. Visit %s for further information " "about the software."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -144,6 +153,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Prune: last wallet synchronisation goes beyond pruned data. You need to -" "reindex (download the whole blockchain again in case of pruned node)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate " +"leveldb directory."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "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."), @@ -156,6 +168,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "rebuild the block database if you are sure that your computer's date and " "time are correct"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"The combination of the pre-selected inputs and the wallet automatic inputs " +"selection exceeds the transaction maximum weight. Please try sending a " +"smaller amount or manually consolidating your wallet's UTXOs"), +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", "" @@ -236,14 +252,25 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "You need to rebuild the database using -reindex to go back to unpruned " "mode. This will redownload the entire blockchain"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Your computer's date and time appear to be more than %d minutes out of sync " +"with the network, this may lead to consensus failure. After you've confirmed " +"your computer's clock, this message should no longer appear when you restart " +"your node. Without a restart, it should stop showing automatically after " +"you've connected to a sufficient number of new outbound peers, which may " +"take some time. You can inspect the `timeoffset` field of the `getpeerinfo` " +"and `getnetworkinfo` RPC methods to get more info."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "\n" "Unable to cleanup failed migration"), QT_TRANSLATE_NOOP("bitcoin-core", "" "\n" "Unable to restore backup of wallet."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"whitebind may only be used for incoming connections (\"out\" was passed)"), QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), -QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"), +QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details: "), +QT_TRANSLATE_NOOP("bitcoin-core", "Assumeutxo data not found for the given blockhash '%s'."), QT_TRANSLATE_NOOP("bitcoin-core", "Block verification was interrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -forcednsseed to true when setting -dnsseed to false."), @@ -251,6 +278,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -peerblockfilters without -blockfi QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write to data directory '%s'; check permissions."), QT_TRANSLATE_NOOP("bitcoin-core", "Config setting for %s only applied on %s network when in [%s] section."), QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) %i-%i"), +QT_TRANSLATE_NOOP("bitcoin-core", "Corrupt block found indicating potential hardware failure."), QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Could not find asmap file %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Could not parse asmap file %s"), @@ -258,6 +286,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Disk space is too low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), QT_TRANSLATE_NOOP("bitcoin-core", "Dump file %s does not exist."), +QT_TRANSLATE_NOOP("bitcoin-core", "Elliptic curve cryptography sanity check failure. %s is shutting down."), QT_TRANSLATE_NOOP("bitcoin-core", "Error committing db txn for wallet transactions removal"), QT_TRANSLATE_NOOP("bitcoin-core", "Error creating %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), @@ -297,10 +326,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to write solvable wallet best b QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to write watchonly wallet best block locator record"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: address book copy failed for wallet %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: database transaction cannot be executed for wallet %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to connect best block (%s)."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to disconnect block."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to start indexes, shutting down.."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to verify database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to block index database."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database."), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data."), QT_TRANSLATE_NOOP("bitcoin-core", "Failure removing transaction: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Fee rate (%s) is lower than the minimum fee rate setting (%s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Ignoring duplicate -wallet %s."), @@ -325,6 +361,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet…"), +QT_TRANSLATE_NOOP("bitcoin-core", "Maximum transaction weight must be between %d and %d"), QT_TRANSLATE_NOOP("bitcoin-core", "Missing amount"), QT_TRANSLATE_NOOP("bitcoin-core", "Missing solving data for estimating transaction size"), QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"), @@ -332,6 +369,7 @@ 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", "Only direction was set, no permissions: '%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…"), @@ -345,6 +383,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Unexpected application id. Ex QT_TRANSLATE_NOOP("bitcoin-core", "Section [%s] is not recognized."), QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be read"), QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be written"), +QT_TRANSLATE_NOOP("bitcoin-core", "Signer did not echo address"), +QT_TRANSLATE_NOOP("bitcoin-core", "Signer echoed unexpected address %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Signer returned error: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" does not exist"), QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is a relative path"), @@ -352,10 +393,14 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a director QT_TRANSLATE_NOOP("bitcoin-core", "Specified blocks directory \"%s\" does not exist."), QT_TRANSLATE_NOOP("bitcoin-core", "Specified data directory \"%s\" does not exist."), QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads…"), +QT_TRANSLATE_NOOP("bitcoin-core", "System error while flushing: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "System error while loading external block file: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "System error while saving block to disk: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."), QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist"), QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"), QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."), +QT_TRANSLATE_NOOP("bitcoin-core", "There is no ScriptPubKeyManager for this address"), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), QT_TRANSLATE_NOOP("bitcoin-core", "This is the minimum transaction fee you pay on every transaction."), QT_TRANSLATE_NOOP("bitcoin-core", "This is the transaction fee you will pay if you send a transaction."), @@ -366,7 +411,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction change output index out of range" QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction needs a change address, but we can't generate it."), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"), -QT_TRANSLATE_NOOP("bitcoin-core", "Unable to allocate memory for -maxsigcachesize: '%s' MiB"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"), @@ -382,6 +426,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown change type '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown new rules activated (versionbit %i)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unrecognised option \"%s\" provided in -test=<option>."), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported global logging level %s=%s. Valid values: %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."), QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."), diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 2f3bad37e6..5c70c2695c 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -53,7 +53,7 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO connect(timer, &QTimer::timeout, [this] { // no locking required at this point // the following calls will acquire the required lock - Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage()); + Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage(), m_node.getMempoolMaxUsage()); Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent()); }); connect(m_thread, &QThread::finished, timer, &QObject::deleteLater); @@ -123,6 +123,13 @@ int64_t ClientModel::getHeaderTipTime() const return cachedBestHeaderTime; } + +std::map<CNetAddr, LocalServiceInfo> ClientModel::getNetLocalAddresses() const +{ + return m_node.getNetLocalAddresses(); +} + + int ClientModel::getNumBlocks() const { if (m_cached_num_blocks == -1) { diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 624056b5df..7d0e35e7f9 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -13,12 +13,15 @@ #include <sync.h> #include <uint256.h> +#include <netaddress.h> + class BanTableModel; class CBlockIndex; class OptionsModel; class PeerTableModel; class PeerTableSortProxy; enum class SynchronizationState; +struct LocalServiceInfo; namespace interfaces { class Handler; @@ -68,6 +71,7 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; + std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() const; int getNumBlocks() const; uint256 getBestBlockHash() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex); int getHeaderTipHeight() const; @@ -113,7 +117,7 @@ private: Q_SIGNALS: void numConnectionsChanged(int count); void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state); - void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); + void mempoolSizeChanged(long count, size_t mempoolSizeInBytes, size_t mempoolMaxSizeInBytes); void networkActiveChanged(bool networkActive); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 5e412bd6b1..febf1ee82f 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -174,22 +174,17 @@ void CoinControlDialog::showMenu(const QPoint &point) contextMenuItem = item; // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu - if (item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode) - { + auto txid{Txid::FromHex(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString())}; + if (txid) { // a valid txid means this is a child node, and not a parent node in tree mode m_copy_transaction_outpoint_action->setEnabled(true); - if (model->wallet().isLockedCoin(COutPoint(TxidFromString(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt()))) - { + if (model->wallet().isLockedCoin(COutPoint(*txid, item->data(COLUMN_ADDRESS, VOutRole).toUInt()))) { lockAction->setEnabled(false); unlockAction->setEnabled(true); - } - else - { + } else { lockAction->setEnabled(true); unlockAction->setEnabled(false); } - } - else // this means click on parent node in tree mode -> disable all - { + } else { // this means click on parent node in tree mode -> disable all m_copy_transaction_outpoint_action->setEnabled(false); lockAction->setEnabled(false); unlockAction->setEnabled(false); @@ -240,7 +235,7 @@ void CoinControlDialog::lockCoin() if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - COutPoint outpt(TxidFromString(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt()); + COutPoint outpt(Txid::FromHex(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()).value(), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt()); model->wallet().lockCoin(outpt, /* write_to_db = */ true); contextMenuItem->setDisabled(true); contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); @@ -250,7 +245,7 @@ void CoinControlDialog::lockCoin() // context menu action: unlock coin void CoinControlDialog::unlockCoin() { - COutPoint outpt(TxidFromString(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt()); + COutPoint outpt(Txid::FromHex(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()).value(), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt()); model->wallet().unlockCoin(outpt); contextMenuItem->setDisabled(false); contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon()); @@ -340,9 +335,10 @@ void CoinControlDialog::radioListMode(bool checked) // checkbox clicked by user void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) { - if (column == COLUMN_CHECKBOX && item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode) - { - COutPoint outpt(TxidFromString(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt()); + if (column != COLUMN_CHECKBOX) return; + auto txid{Txid::FromHex(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString())}; + if (txid) { // a valid txid means this is a child node, and not a parent node in tree mode + COutPoint outpt(*txid, item->data(COLUMN_ADDRESS, VOutRole).toUInt()); if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) m_coin_control.UnSelect(outpt); diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index eeea53864a..eccea14318 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -249,6 +249,41 @@ </widget> </item> <item row="9" column="0"> + <widget class="QLabel" name="label_14"> + <property name="text"> + <string>Local Addresses</string> + </property> + </widget> + </item> + <item row="9" column="1" colspan="2"> + <widget class="QLabel" name="localAddresses"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string notr="true">N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + <property name="toolTip"> + <string>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</string> + </property> + </widget> + </item> + <item row="10" column="0"> <widget class="QLabel" name="label_10"> <property name="font"> <font> @@ -261,14 +296,14 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Current block height</string> </property> </widget> </item> - <item row="10" column="1" colspan="2"> + <item row="11" column="1" colspan="2"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -284,14 +319,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="labelLastBlockTime"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="11" column="1" colspan="2"> + <item row="12" column="1" colspan="2"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -307,7 +342,7 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="labelMempoolTitle"> <property name="font"> <font> @@ -320,14 +355,14 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="labelNumberOfTransactions"> <property name="text"> <string>Current number of transactions</string> </property> </widget> </item> - <item row="13" column="1"> + <item row="14" column="1"> <widget class="QLabel" name="mempoolNumberTxs"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -343,14 +378,14 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="15" column="0"> <widget class="QLabel" name="labelMemoryUsage"> <property name="text"> <string>Memory usage</string> </property> </widget> </item> - <item row="14" column="1"> + <item row="15" column="1"> <widget class="QLabel" name="mempoolSize"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -366,7 +401,7 @@ </property> </widget> </item> - <item row="12" column="2" rowspan="3"> + <item row="13" column="2" rowspan="3"> <layout class="QVBoxLayout" name="verticalLayoutDebugButton"> <property name="spacing"> <number>3</number> @@ -406,7 +441,7 @@ </item> </layout> </item> - <item row="15" column="0"> + <item row="16" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -984,42 +1019,117 @@ </size> </property> <layout class="QVBoxLayout" name="verticalLayout_8"> - <item> - <widget class="QLabel" name="peerHeading"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>32</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>10</pointsize> - </font> - </property> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="text"> - <string>Select a peer to view detailed information.</string> - </property> - <property name="alignment"> - <set>Qt::AlignHCenter|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <property name="topMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="peerHeading"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>Select a peer to view detailed information.</string> + </property> + <property name="alignment"> + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="hidePeersDetail" native="true"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <widget class="QToolButton" name="hidePeersDetailButton"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>32</width> + <height>32</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Hide Peers Detail</string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string /> + </property> + <property name="icon"> + <iconset resource="../bitcoin.qrc"> + <normaloff>:/icons/remove</normaloff> + :/icons/remove + </iconset> + </property> + <property name="iconSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="shortcut"> + <string>Ctrl+X</string> + </property> + </widget> + </widget> + </item> + </layout> + </item> <item> <widget class="QScrollArea" name="scrollArea"> <property name="widgetResizable"> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 0386689baf..30ffa302a4 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -50,6 +50,7 @@ static const int TOOLTIP_WRAP_THRESHOLD = 80; #define QAPP_ORG_DOMAIN "bitcoin.org" #define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt" #define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet" +#define QAPP_APP_NAME_TESTNET4 "Bitcoin-Qt-testnet4" #define QAPP_APP_NAME_SIGNET "Bitcoin-Qt-signet" #define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest" diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index ee841ce626..2369f6b631 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -2,8 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <config/bitcoin-config.h> // IWYU pragma: keep - #include <qt/guiutil.h> #include <qt/bitcoinaddressvalidator.h> @@ -117,6 +115,7 @@ static std::string DummyAddress(const CChainParams ¶ms) break; case ChainType::SIGNET: case ChainType::TESTNET: + case ChainType::TESTNET4: addr = "tb1p35yvjel7srp783ztf8v6jdra7dhfzk5jaun8xz2qp6ws7z80n4tqa6qnlg"; break; case ChainType::REGTEST: @@ -406,19 +405,26 @@ bool isObscured(QWidget *w) void bringToFront(QWidget* w) { -#ifdef Q_OS_MACOS - ForceActivation(); -#endif - if (w) { - // activateWindow() (sometimes) helps with keyboard focus on Windows - if (w->isMinimized()) { - w->showNormal(); - } else { + if (QGuiApplication::platformName() == "wayland") { + auto flags = w->windowFlags(); + w->setWindowFlags(flags|Qt::WindowStaysOnTopHint); w->show(); + w->setWindowFlags(flags); + w->show(); + } else { +#ifdef Q_OS_MACOS + ForceActivation(); +#endif + // activateWindow() (sometimes) helps with keyboard focus on Windows + if (w->isMinimized()) { + w->showNormal(); + } else { + w->show(); + } + w->activateWindow(); + w->raise(); } - w->activateWindow(); - w->raise(); } } @@ -918,29 +924,24 @@ void LogQtInfo() #else const std::string qt_link{"dynamic"}; #endif -#ifdef QT_STATICPLUGIN - const std::string plugin_link{"static"}; -#else - const std::string plugin_link{"dynamic"}; -#endif - LogPrintf("Qt %s (%s), plugin=%s (%s)\n", qVersion(), qt_link, QGuiApplication::platformName().toStdString(), plugin_link); + LogInfo("Qt %s (%s), plugin=%s\n", qVersion(), qt_link, QGuiApplication::platformName().toStdString()); const auto static_plugins = QPluginLoader::staticPlugins(); if (static_plugins.empty()) { - LogPrintf("No static plugins.\n"); + LogInfo("No static plugins.\n"); } else { - LogPrintf("Static plugins:\n"); + LogInfo("Static plugins:\n"); for (const QStaticPlugin& p : static_plugins) { QJsonObject meta_data = p.metaData(); const std::string plugin_class = meta_data.take(QString("className")).toString().toStdString(); const int plugin_version = meta_data.take(QString("version")).toInt(); - LogPrintf(" %s, version %d\n", plugin_class, plugin_version); + LogInfo(" %s, version %d\n", plugin_class, plugin_version); } } - LogPrintf("Style: %s / %s\n", QApplication::style()->objectName().toStdString(), QApplication::style()->metaObject()->className()); - LogPrintf("System: %s, %s\n", QSysInfo::prettyProductName().toStdString(), QSysInfo::buildAbi().toStdString()); + LogInfo("Style: %s / %s\n", QApplication::style()->objectName().toStdString(), QApplication::style()->metaObject()->className()); + LogInfo("System: %s, %s\n", QSysInfo::prettyProductName().toStdString(), QSysInfo::buildAbi().toStdString()); for (const QScreen* s : QGuiApplication::screens()) { - LogPrintf("Screen: %s %dx%d, pixel ratio=%.1f\n", s->name().toStdString(), s->size().width(), s->size().height(), s->devicePixelRatio()); + LogInfo("Screen: %s %dx%d, pixel ratio=%.1f\n", s->name().toStdString(), s->size().width(), s->size().height(), s->devicePixelRatio()); } } @@ -1007,4 +1008,13 @@ void ShowModalDialogAsynchronously(QDialog* dialog) dialog->show(); } +QString WalletDisplayName(const QString& name) +{ + return name.isEmpty() ? "[" + QObject::tr("default wallet") + "]" : name; +} + +QString WalletDisplayName(const std::string& name) +{ + return WalletDisplayName(QString::fromStdString(name)); +} } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 3e28e54557..4525198794 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -436,6 +436,9 @@ namespace GUIUtil return false; } + QString WalletDisplayName(const std::string& name); + QString WalletDisplayName(const QString& name); + } // namespace GUIUtil #endif // BITCOIN_QT_GUIUTIL_H diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index e58c221a86..e703352aa5 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -2,34 +2,6 @@ <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>&New</source> - <translation type="unfinished">&جديد</translation> - </message> - <message> - <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">‫انسخ العنوان المØدد للØاÙظة‬</translation> - </message> - <message> - <source>&Copy</source> - <translation type="unfinished">&نسخ</translation> - </message> - <message> - <source>C&lose</source> - <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> @@ -42,62 +14,10 @@ <translation type="unfinished">&تصدير</translation> </message> <message> - <source>&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&hoose</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">هذه عناوين البتكوين الخاصة بك لاستلام المدÙوعات. قم بالنقر على زر انشاء عنوان استلام جديد لإنشاء عناوين جديدة. -التوقيع ممكن باستخدام العناوين القديمة "Legacy" Ùقط.</translation> - </message> - <message> - <source>&Copy Address</source> - <translation type="unfinished">&نسخ العنوان</translation> - </message> - <message> - <source>Copy &Label</source> - <translation type="unfinished">نسخ &المذكرة</translation> - </message> - <message> - <source>&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> <context> <name>AddressTableModel</name> <message> @@ -1639,11 +1559,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">‫تÙعيل التØكم ب &المعاملات الموقعة جزئيا‬</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> </message> diff --git a/src/qt/locale/bitcoin_az.ts b/src/qt/locale/bitcoin_az.ts index 3bba7a2b40..fcb85f3553 100644 --- a/src/qt/locale/bitcoin_az.ts +++ b/src/qt/locale/bitcoin_az.ts @@ -2,6 +2,10 @@ <context> <name>AddressBookPage</name> <message> + <source>Right-click to edit address or label</source> + <translation type="unfinished">Ãœnvanı vÉ™ ya etiketi redaktÉ™ etmÉ™k üçün saÄŸ kliklÉ™yin</translation> + </message> + <message> <source>Create a new address</source> <translation type="unfinished">Yeni ünvan yaradın</translation> </message> @@ -281,43 +285,43 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> @@ -881,7 +885,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> </message> <message> <source>&Unlock unspent</source> - <translation type="unfinished">XÉ™rclÉ™nmÉ™miÅŸ qalığı kilidd'n &çıxarın</translation> + <translation type="unfinished">XÉ™rclÉ™nmÉ™miÅŸ qalığı kiliddÉ™n &çıxarın</translation> </message> <message> <source>Copy quantity</source> @@ -946,7 +950,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> </message> <message> <source>Can't list signers</source> - <translation type="unfinished">Ä°mzalaynları göstÉ™rmÉ™k mümkün deyil</translation> + <translation type="unfinished">Ä°mzalayanları göstÉ™rmÉ™k mümkün deyil</translation> </message> </context> <context> @@ -954,7 +958,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> + <translation type="unfinished">Pulqabıları yüklÉ™yin</translation> </message> <message> <source>Loading wallets…</source> @@ -963,6 +967,13 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Pulqabını köçür</translation> + </message> + </context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -974,12 +985,12 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">standart cüzdan</translation> + <translation type="unfinished">standart pulqabı</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> + <translation type="unfinished">Pulqabını açın</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</source> @@ -992,7 +1003,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> + <translation type="unfinished">Pulqabını bÉ™rpa et</translation> </message> <message> <source>Restoring Wallet <b>%1</b>…</source> @@ -1002,24 +1013,24 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> + <translation type="unfinished">Pulqabı 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> + <translation type="unfinished">Pulqabını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> + <translation type="unfinished">Pulqabını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> + <translation type="unfinished">Pulqabını baÄŸlayın</translation> </message> <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> @@ -1042,7 +1053,7 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <name>CreateWalletDialog</name> <message> <source>Create Wallet</source> - <translation type="unfinished">Cüzdan yaradın</translation> + <translation type="unfinished">Pulqabı yaradın</translation> </message> <message> <source>Wallet Name</source> @@ -1136,30 +1147,30 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB of space available</numerusform> + <numerusform>%n GB of space available</numerusform> </translation> </message> <message numerus="yes"> <source>(of %n GB needed)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <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 /> - <numerusform /> + <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"> - <numerusform /> - <numerusform /> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> <message> @@ -1457,8 +1468,8 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> @@ -1479,8 +1490,8 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> diff --git a/src/qt/locale/bitcoin_az@latin.ts b/src/qt/locale/bitcoin_az@latin.ts index bb808eaddb..b392a60287 100644 --- a/src/qt/locale/bitcoin_az@latin.ts +++ b/src/qt/locale/bitcoin_az@latin.ts @@ -285,43 +285,43 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> @@ -1140,30 +1140,30 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB of space available</numerusform> + <numerusform>%n GB of space available</numerusform> </translation> </message> <message numerus="yes"> <source>(of %n GB needed)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <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 /> - <numerusform /> + <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"> - <numerusform /> - <numerusform /> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> <message> @@ -1461,8 +1461,8 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> @@ -1483,8 +1483,8 @@ Daxil olma, yalnız 'qanuni' tipli ünvanlar ilÉ™ mümkündür.</translation> <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> diff --git a/src/qt/locale/bitcoin_be.ts b/src/qt/locale/bitcoin_be.ts index f53ba3f5b2..9b6445ff24 100644 --- a/src/qt/locale/bitcoin_be.ts +++ b/src/qt/locale/bitcoin_be.ts @@ -83,6 +83,14 @@ <translation type="unfinished">ÐдбылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ° Ð¿Ð°Ð´Ñ‡Ð°Ñ Ñпробы захаваць Ð°Ð´Ñ€Ð°Ñ Ñƒ %1. ПаÑпрабуйце зноў.</translation> </message> <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">ÐдраÑÑ‹ адпраўкі - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">ÐдраÑÑ‹ Ð¿Ñ€Ñ‹Ð¼Ð°Ð½Ð½Ñ - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">ÐкÑпартаванне нÑўдалае</translation> </message> @@ -157,6 +165,10 @@ <translation type="unfinished">Гаманец зашыфраваны</translation> </message> <message> + <source>Wallet to be 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> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 7eefe113ce..e7bb0d50e0 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -1500,7 +1500,11 @@ 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> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">ÐеизвеÑтно. Предварителна ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° хедъри (%1, %2%)…</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 2ea1e0a2a2..d668c2d13f 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -311,6 +311,12 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <translation type="unfinished">No encaminable</translation> </message> <message> + <source>Onion</source> + <comment>network name</comment> + <extracomment>Name of Tor network in peer info</extracomment> + <translation type="unfinished">Ceba</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">Entrant</translation> @@ -347,36 +353,36 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n segons</numerusform> + <numerusform>%n segon(s)</numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n minuts</numerusform> + <numerusform>%n minuts</numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n hores</numerusform> + <numerusform>%n hores</numerusform> </translation> </message> <message numerus="yes"> <source>%n day(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n dies</numerusform> + <numerusform>%n dies</numerusform> </translation> </message> <message numerus="yes"> <source>%n week(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n setmanes</numerusform> + <numerusform>%n setmanes</numerusform> </translation> </message> <message> @@ -386,8 +392,8 @@ Només és possible firmar amb adreces del tipus "legacy".</translation> <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n any</numerusform> + <numerusform>%n anys</numerusform> </translation> </message> </context> @@ -1136,7 +1142,22 @@ El procés de migració crearà una còpia de seguretat de la cartera abans de m <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment> <translation type="unfinished">Restaurant cartera <b>%1</b>...</translation> </message> - </context> + <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">Reestablir cartera ha fallat</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">AvÃs al restaurar la cartera</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">Missatge al restaurar la cartera</translation> + </message> +</context> <context> <name>WalletController</name> <message> @@ -1167,6 +1188,14 @@ El procés de migració crearà una còpia de seguretat de la cartera abans de m <translation type="unfinished">Crear cartera</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Només et queda un pas per a crear la teva nova cartera</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">Si us plau, proporciona un nom i, si vols, activa qualsevol opció avançada</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Nom de la cartera</translation> </message> @@ -1304,8 +1333,8 @@ Això és ideal per a carteres de mode només lectura.</translation> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB d'espai lliure disponible</numerusform> + <numerusform>%n GB d'espai lliure disponibles</numerusform> </translation> </message> <message numerus="yes"> @@ -1379,6 +1408,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">Aquesta sincronització inicial és molt exigent i pot exposar problemes de maquinari amb l'equip que anteriorment havien passat desapercebuts. Cada vegada que executeu %1, continuarà descarregant des del punt on es va deixar.</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">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>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 heu decidit limitar l'emmagatzematge de la cadena de blocs (podar), les dades històriques encara s'hauran de baixar i processar, però se suprimiran més endavant per a mantenir baix l'ús del disc.</translation> </message> @@ -1471,7 +1504,11 @@ 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> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Desconegut. Sincronització de les capçaleres (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -1527,6 +1564,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">Minimitza en comptes de sortir de l'aplicació quan la finestra es tanca. Quan s'habilita aquesta opció l'aplicació es tancarà només quan se selecciona Surt del menú. </translation> </message> <message> + <source>Options set in this dialog are overridden by the command line:</source> + <translation type="unfinished">Les opcions configurades en aquest dià leg són sobreescrites per la lÃnia de comandes:</translation> + </message> + <message> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished">Obriu el fitxer de configuració %1 des del directori de treball.</translation> </message> @@ -1559,6 +1600,11 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">(0 = auto, <0 = deixa tants nuclis lliures)</translation> </message> <message> + <source>Enable R&PC server</source> + <extracomment>An Options window setting to enable the RPC server.</extracomment> + <translation type="unfinished">Activa el servidor R&PC</translation> + </message> + <message> <source>W&allet</source> <translation type="unfinished">&Moneder</translation> </message> @@ -1575,6 +1621,11 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">&Gasta el canvi sense confirmar</translation> </message> <message> + <source>Enable &PSBT controls</source> + <extracomment>An options window setting to enable PSBT controls.</extracomment> + <translation type="unfinished">Activa els controls &PSBT</translation> + </message> + <message> <source>External Signer (e.g. hardware wallet)</source> <translation type="unfinished">Signador extern (per exemple, cartera de maquinari)</translation> </message> @@ -1671,6 +1722,14 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">Selecciona la unitat de subdivisió per defecte per a mostrar en la interfÃcie quan s'envien monedes.</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 de terceres parts (p. ex. explorador de blocs) que apareix en la pestanya de transaccions com elements del menú contextual. %s en l'URL es reemplaçat pel resum de la transacció. Diferents URL estan separades per una barra vertical |.</translation> + </message> + <message> + <source>&Third-party transaction URLs</source> + <translation type="unfinished">URL de transaccions de tercers</translation> + </message> + <message> <source>Whether to show coin control features or not.</source> <translation type="unfinished">Si voleu mostrar les funcions de control de monedes o no.</translation> </message> @@ -1729,6 +1788,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">El fitxer de configuració s'utilitza per a especificar les opcions d'usuari avançades que substitueixen la configuració de la interfÃcie grà fica d'usuari. A més, qualsevol opció de la lÃnia d'ordres substituirà aquest fitxer de configuració.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Continua</translation> + </message> + <message> <source>Cancel</source> <translation type="unfinished">Cancel·la</translation> </message> @@ -1819,6 +1882,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <context> <name>PSBTOperationsDialog</name> <message> + <source>PSBT Operations</source> + <translation type="unfinished">Operacions PSBT</translation> + </message> + <message> <source>Sign Tx</source> <translation type="unfinished">Signa Tx</translation> </message> @@ -1916,6 +1983,10 @@ Això és ideal per a carteres de mode només lectura.</translation> <translation type="unfinished">La transacció encara necessita una o và ries firmes.</translation> </message> <message> + <source>(But no wallet is loaded.)</source> + <translation type="unfinished">(Cap cartera ha estat carregada.)</translation> + </message> + <message> <source>(But this wallet cannot sign transactions.)</source> <translation type="unfinished">(Però aquesta cartera no pot firmar transaccions.)</translation> </message> @@ -1980,6 +2051,11 @@ Si rebeu aquest error, haureu de sol·licitar al comerciant que proporcioni un U <translation type="unfinished">Igual</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">Edat</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ó</translation> @@ -2864,6 +2940,11 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k <translation type="unfinished">Si us plau, revisa la teva proposta de transacció. Es produirà una transacció de Bitcoin amb firma parcial (PSBT) que podeu guardar o copiar i després firmar, per exemple, amb una cartera %1, o amb una cartera fÃsica compatible amb 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">Voleu crear aquesta transacció?</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">Reviseu la transacció</translation> @@ -3247,8 +3328,10 @@ Nota: atès que la tarifa es calcula per byte, una tarifa de "100 satoshis per k <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>madura en %n bloc més +</numerusform> + <numerusform>madura en %n blocs més +</numerusform> </translation> </message> <message> @@ -3897,6 +3980,23 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">No es pot escriure en el directori de dades "%s". Reviseu-ne els permisos.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">%s especificat molt alt! Tarifes tan grans podrien pagar-se en una única transacció. +</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> + <translation type="unfinished">S'ha produït un error en llegir %s. Totes les claus es llegeixen correctament, però les dades de la transacció o les entra des de la llibreta d'adreces podrien faltar o ser incorrectes.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">L'estimació de la quota ha fallat. Fallbackfee està desactivat. Espereu uns quants blocs o activeu %s.</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation type="unfinished">Import no và lid per a %s=<amount>: '%s' (cal que sigui com a mÃnim la comissió de minrelay de %s per evitar que les comissions s'encallin)</translation> + </message> + <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished">Configuració per a %s únicament aplicada a %s de la xarxa quan es troba a la secció [%s].</translation> </message> @@ -4070,6 +4170,14 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">PermÃs P2P no và lid: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">Import no và lid per a %s=<amount>: «%s» (ha de ser com a mÃnim %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Import invà lid per a %s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Import invà lid per a -%s=<amount>: '%s'</translation> </message> @@ -4078,6 +4186,10 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">S'ha especificat una mà scara de xarxa no và lida a -whitelist: «%s»</translation> </message> <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">ha fallat escoltar les connexions entrants (l'escoltament ha retornat l'error %s)</translation> + </message> + <message> <source>Loading P2P addresses…</source> <translation type="unfinished">S'estan carregant les adreces P2P...</translation> </message> @@ -4166,6 +4278,10 @@ Ves a Arxiu > Obrir Cartera per a carregar cartera. <translation type="unfinished">El directori de blocs especificat "%s" no existeix.</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">El directori de dades especificat «%s» no existeix.</translation> + </message> + <message> <source>Starting network threads…</source> <translation type="unfinished">S'estan iniciant fils de xarxa...</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 5f2ffc5bd0..e817e0b40e 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -4148,6 +4148,12 @@ Ověřuji peněženku.</translation> <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 reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</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 moho +u chybÄ›t Äi být nesprávné. +</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> @@ -4730,6 +4736,10 @@ Nelze obnovit zálohu peněženky.</translation> <translation type="unfinished">Nepodporovaná logovacà kategorie %s=%s.</translation> </message> <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">Chyba: Nelze pÅ™idat pouze-sledovacà tx %s do peněženky pro ÄtenÃ</translation> + </message> + <message> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished">Komentář u typu klienta (%s) obsahuje riskantnà znaky.</translation> </message> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 53a4f6a223..f3b153d3f7 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -1187,8 +1187,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB fri plads tilgængelig</numerusform> + <numerusform>%n GB fri plads tilgængelig</numerusform> </translation> </message> <message numerus="yes"> @@ -1266,6 +1266,10 @@ Signing is only possible with addresses of the type 'legacy'.</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> <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">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> + </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">Hvis du har valgt at begrænse opbevaringen af blokkæden (beskæring/pruning), vil al historisk data stadig skulle downloades og bearbejdes men vil blive slettet efterfølgende for at holde dit diskforbrug lavt.</translation> </message> @@ -1398,6 +1402,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Antallet af script&verificeringstrÃ¥de</translation> </message> <message> + <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">Fuld sti til et %1-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>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">IP-adresse for proxyen (fx IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -3888,6 +3896,10 @@ GÃ¥ til Fil > Ã…bn Pung for, at indlæse en pung. <translation type="unfinished">Kan ikke skrive til datamappe '%s'; tjek tilladelser.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">%s er sat meget højt! Gebyrer sÃ¥ store risikeres betalt pÃ¥ en enkelt transaktion.</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> @@ -3896,10 +3908,22 @@ GÃ¥ til Fil > Ã…bn Pung for, at indlæse en pung. <translation type="unfinished">Fejlindlæsning %s: Ekstern underskriver-tegnebog indlæses uden ekstern underskriverunderstøttelse kompileret</translation> </message> <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</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>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>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">Estimering af gebyr mislykkedes. Tilbagefaldsgebyr er deaktiveret. Vent et par blokke eller aktiver %s.</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation type="unfinished">Ugyldigt beløb for %s=<beløb>: “%s†(skal være pÃ¥ mindst minrelay-gebyret pÃ¥ %s for at undgÃ¥ hængende transaktioner)</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> @@ -4076,6 +4100,14 @@ GÃ¥ til Fil > Ã…bn Pung for, at indlæse en pung. <translation type="unfinished">Invalid P2P tilladelse: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">Ugyldigt beløb for %s=<beløb>: “%s†(skal være mindst %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Ugyldigt beløb for %s=<beløb>: “%sâ€</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Ugyldigt beløb for -%s=<beløb>: “%sâ€</translation> </message> @@ -4084,6 +4116,11 @@ GÃ¥ til Fil > Ã…bn Pung for, at indlæse en pung. <translation type="unfinished">Ugyldig netmaske angivet i -whitelist: “%sâ€</translation> </message> <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">Lytning efter indkommende forbindelser mislykkedes (lytning resultarede i fejl %s) +</translation> + </message> + <message> <source>Loading P2P addresses…</source> <translation type="unfinished">Indlæser P2P-adresser...</translation> </message> @@ -4184,6 +4221,10 @@ GÃ¥ til Fil > Ã…bn Pung for, at indlæse en pung. <translation type="unfinished">Angivet blokmappe “%s†eksisterer ikke.</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">Angivet datamappe “%s†eksisterer ikke.</translation> + </message> + <message> <source>Starting network threads…</source> <translation type="unfinished">Starter netværkstrÃ¥de...</translation> </message> diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index e7a3710dfb..8a73df2627 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -366,10 +366,6 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">%1 T</translation> </message> <message> - <source>%1 h</source> - <translation type="unfinished">%1 S</translation> - </message> - <message> <source>%1 m</source> <translation type="unfinished">%1 min</translation> </message> @@ -1226,7 +1222,7 @@ Während des Migrationsprozesses wird vor der Migration ein Backup der Wallet er </message> <message> <source>You are one step away from creating your new wallet!</source> - <translation type="unfinished">Nur noch einen Schritt entfernt, das neue Wallet zu erstellen!</translation> + <translation type="unfinished">Nur noch einen Schritt entfernt um das neue Wallet zu erstellen!</translation> </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> @@ -2169,7 +2165,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI <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">Ãœbertragen</translation> + <translation type="unfinished">Gesendet</translation> </message> <message> <source>Received</source> @@ -2310,7 +2306,7 @@ Wenn Sie diese Fehlermeldung erhalten, sollten Sie den Händler bitten, einen BI </message> <message> <source>Sent</source> - <translation type="unfinished">Ãœbertragen</translation> + <translation type="unfinished">Gesendet</translation> </message> <message> <source>&Peers</source> @@ -2685,7 +2681,7 @@ Benutze %3 und %4, um die Fontgröße zu vergrößern bzw. verkleinern. Tippe %5 für einen Ãœberblick über verfügbare Befehle. Für weitere Informationen über diese Konsole, tippe %6. -%7 ACHTUNG: Es sind Betrüger zu Gange, die Benutzer anweisen, hier Kommandos einzugeben, wodurch sie den Inhalt der Wallet stehlen können. Benutze diese Konsole nicht, ohne die Implikationen eines Kommandos vollständig zu verstehen.%8</translation> +%7ACHTUNG: Es sind Betrüger zu Gange, die Benutzer anweisen, hier Kommandos einzugeben, wodurch sie den Inhalt der Wallet stehlen können. Benutze diese Konsole nicht, ohne die Implikationen eines Kommandos vollständig zu verstehen.%8</translation> </message> <message> <source>Executing…</source> @@ -3042,7 +3038,7 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre </message> <message> <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">Eine niedrige Gebühr kann dazu führen das eine Transaktion niemals bestätigt wird (Lesen sie die Anmerkung).</translation> + <translation type="unfinished">Eine niedrige Gebühr kann dazu führen das eine Transaktion niemals bestätigt wird (Lesen Sie die Anmerkung).</translation> </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> @@ -3124,7 +3120,7 @@ Hinweis: Da die Gebühr auf Basis der Bytes berechnet wird, führt eine Gebühre </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">Erzeugt eine teilsignierte Bitcoin Transaktion (PSBT) zur Benutzung mit z.B. einem Offline %1 Wallet, oder einem kompatiblen Hardware Wallet.</translation> + <translation type="unfinished">Erzeugt eine teilsignierte Bitcoin Transaktion (PSBT) zur Benutzung mit z.B. einem Offline %1 Wallet oder einem kompatiblen Hardware Wallet.</translation> </message> <message> <source>%1 to '%2'</source> diff --git a/src/qt/locale/bitcoin_de_CH.ts b/src/qt/locale/bitcoin_de_CH.ts index 2792a1bc98..12e648ff38 100644 --- a/src/qt/locale/bitcoin_de_CH.ts +++ b/src/qt/locale/bitcoin_de_CH.ts @@ -23,7 +23,7 @@ </message> <message> <source>C&lose</source> - <translation type="unfinished">&Schließen</translation> + <translation type="unfinished">&Schliessen</translation> </message> <message> <source>Delete the currently selected address from the list</source> @@ -447,6 +447,18 @@ Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> <translation type="unfinished">Neues Wallet erstellen</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished">&Minimieren</translation> + </message> + <message> + <source>&Send</source> + <translation type="unfinished">&Senden</translation> + </message> + <message> + <source>&Receive</source> + <translation type="unfinished">&Empfangen</translation> + </message> + <message> <source>&Options…</source> <translation type="unfinished">weitere Möglichkeiten/Einstellungen </translation> </message> diff --git a/src/qt/locale/bitcoin_el.ts b/src/qt/locale/bitcoin_el.ts index 61d6807947..d0caab7330 100644 --- a/src/qt/locale/bitcoin_el.ts +++ b/src/qt/locale/bitcoin_el.ts @@ -283,6 +283,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">άγνωστο</translation> </message> <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Î ÏοεπιλεγμÎνη γÏαμματοσειÏά συστήματος "%1"</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Ποσό</translation> </message> @@ -2319,10 +2323,22 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Η συμβολοσειÏά αναγνωÏÎ¹ÏƒÏ„Î¹ÎºÎ¿Ï Ï€ÎµÏιόδου σÏνδεσης BIP324 σε δεκαεξαδική μοÏφή, εάν υπάÏχει.</translation> </message> <message> + <source>Session ID</source> + <translation type="unfinished">ΑναγνωÏιστικό πεÏιόδου σÏνδεσης</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Έκδοση</translation> </message> <message> + <source>Whether we relay transactions to this peer.</source> + <translation type="unfinished">Είτε αναμεταδίδουμε συναλλαγÎÏ‚ σε αυτόν τον ομότιμο.</translation> + </message> + <message> + <source>Transaction Relay</source> + <translation type="unfinished">Αναμετάδοση Συναλλαγής</translation> + </message> + <message> <source>Starting Block</source> <translation type="unfinished">ΑÏχικό Μπλοκ</translation> </message> @@ -2347,6 +2363,36 @@ 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">Agent χÏήστη</translation> </message> @@ -2379,10 +2425,18 @@ If you are receiving this error you should request the merchant provide a BIP21 <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>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> @@ -2391,10 +2445,19 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">Τελευταίο Block</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> @@ -2464,10 +2527,58 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">ΕισεÏχόμενo: Ξεκίνησε από 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">ΠλήÏες ΕξεÏχόμενη Αναμετάδοση: Ï€Ïοεπιλογή</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>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">ανίχνευση: ο ομότιμος μποÏεί να είναι v1 ή v2</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: Ï€Ïωτόκολλο μεταφοÏάς μη κÏυπτογÏαφημÎνου Î±Ï€Î»Î¿Ï ÎºÎµÎ¹Î¼Îνου</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: ΚÏυπτογÏαφημÎνο Ï€Ïωτόκολλο μεταφοÏάς BIP324</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>&Copy address</source> <extracomment>Context menu action to copy the address of a peer.</extracomment> <translation type="unfinished">&ΑντιγÏαφή διεÏθυνσης</translation> @@ -2515,6 +2626,23 @@ If you are receiving this error you should request the merchant provide a BIP21 ΕκτελÎστε εντολή χÏησιμοποιώντας το ποÏτοφόλι "%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> @@ -2647,6 +2775,26 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">ΑντιγÏαφή &ποσοÏ</translation> </message> <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Base58 (Î Î±Î»Î±Î¹Î¿Ï Ï„Ïπου)</translation> + </message> + <message> + <source>Not recommended due to higher fees and less protection against typos.</source> + <translation type="unfinished">Δεν συνιστάται λόγω υψηλότεÏων χÏεώσεων και μικÏότεÏης Ï€Ïοστασίας Îναντι τυπογÏαφικών σφαλμάτων.</translation> + </message> + <message> + <source>Generates an address compatible with older wallets.</source> + <translation type="unfinished">ΠαÏάγει μια διεÏθυνση συμβατή με παλαιότεÏα ποÏτοφόλια.</translation> + </message> + <message> + <source>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> + <translation type="unfinished">ΔημιουÏγεί μια εγγενή διεÏθυνση segwit (BIP-173). ΟÏισμÎνα παλιά ποÏτοφόλια δεν το υποστηÏίζουν.</translation> + </message> + <message> + <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> + <translation type="unfinished">Το Bech32m (BIP-350) είναι μια αναβάθμιση στο Bech32, η υποστήÏιξη ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï ÎµÎ¾Î±ÎºÎ¿Î»Î¿Ï…Î¸ÎµÎ¯ να είναι πεÏιοÏισμÎνη.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation type="unfinished">Δεν είναι δυνατό το ξεκλείδωμα του ποÏτοφολιοÏ.</translation> </message> @@ -2926,6 +3074,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">ΣυνδÎστε Ï€Ïώτα τη συσκευή ποÏÏ„Î¿Ï†Î¿Î»Î¹Î¿Ï ÏƒÎ±Ï‚.</translation> </message> <message> + <source>Set external signer script path in Options -> Wallet</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">ΟÏίστε τη διαδÏομή σεναÏίου εξωτεÏÎ¹ÎºÎ¿Ï Ï…Ï€Î¿Î³Ïάφοντος στις ΕπιλογÎÏ‚ -> ΠοÏτοφόλι</translation> + </message> + <message> <source>Cr&eate Unsigned</source> <translation type="unfinished">Δη&μιουÏγία ΑνυπόγÏαφου</translation> </message> @@ -2951,6 +3104,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <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> @@ -2987,6 +3145,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <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.</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> @@ -3005,6 +3168,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <translation type="unfinished">Συνολικό ποσό</translation> </message> <message> + <source>Unsigned Transaction</source> + <comment>PSBT copied</comment> + <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> + <translation type="unfinished">ΑνυπόγÏαφη Συναλλαγή</translation> + </message> + <message> + <source>The PSBT has been copied to the clipboard. You can also save it.</source> + <translation type="unfinished">Το PSBT αντιγÏάφηκε στο Ï€ÏόχειÏο. ΜποÏείτε, επίσης, να το αποθηκεÏσετε.</translation> + </message> + <message> + <source>PSBT saved to disk</source> + <translation type="unfinished">Το PSBT αποθηκεÏτηκε στον δίσκο</translation> + </message> + <message> <source>Confirm send coins</source> <translation type="unfinished"> Επιβεβαιώστε την αποστολή νομισμάτων</translation> </message> @@ -3043,8 +3220,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satos <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> @@ -3357,8 +3534,8 @@ 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>ωÏιμάζει σε %n πεÏισσότεÏα μπλοκ</numerusform> + <numerusform>ωÏιμάζει σε %n πεÏισσότεÏα κομμάτια</numerusform> </translation> </message> <message> @@ -3962,6 +4139,18 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">ΑδÏνατη η εγγÏαφή στον κατάλογο δεδομÎνων '%s'. ΕλÎγξτε τα δικαιώματα.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">%s είναι καταχωÏημÎνο Ï€Î¿Î»Ï Ï…ÏˆÎ·Î»Î¬! Έξοδα τόσο υψηλά μποÏοÏν να πληÏωθοÏν σε μια ενιαία συναλλαγή.</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> + <translation type="unfinished">Σφάλμα κατά την ανάγνωση %s! Όλα τα κλειδιά διαβάζονται σωστά, αλλά τα δεδομÎνα των συναλλαγών ή οι καταχωÏίσεις του βιβλίου διευθÏνσεων ενδÎχεται να λείπουν ή να είναι εσφαλμÎνα.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">Η αποτίμηση του Ï„Îλους απÎτυχε. Το Fallbackfee είναι απενεÏγοποιημÎνο. ΠεÏιμÎνετε λίγα τετÏάγωνα ή ενεÏγοποιήστε το %s.</translation> + </message> + <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished">Η ÏÏθμιση Config για το %s εφαÏμόστηκε μόνο στο δίκτυο %s όταν βÏίσκεται στην ενότητα [%s].</translation> </message> @@ -4110,6 +4299,10 @@ Go to File > Open Wallet to load a wallet. <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> </message> @@ -4190,6 +4383,10 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Δεν υπάÏχει κατάλογος καθοÏισμÎνων μπλοκ "%s".</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">Ο οÏισμÎνος κατάλογος δεδομÎνων "%s" δεν υπάÏχει.</translation> + </message> + <message> <source>Starting network threads…</source> <translation type="unfinished">Εκκίνηση των threads δικτÏου...</translation> </message> diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 01b428d46e..c8aacee4f3 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="+117"/> + <location filename="../addressbookpage.cpp" line="+113"/> <source>&Delete</source> <translation>&Delete</translation> </message> @@ -179,12 +179,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../askpassphrasedialog.cpp" line="+49"/> + <location filename="../askpassphrasedialog.cpp" line="+45"/> <source>Encrypt wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+4"/> <source>This operation needs your wallet passphrase to unlock the wallet.</source> <translation type="unfinished"></translation> </message> @@ -199,7 +199,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+47"/> + <location line="+48"/> <source>Confirm wallet encryption</source> <translation type="unfinished"></translation> </message> @@ -210,32 +210,43 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+0"/> + <location line="+18"/> <source>Are you sure you wish to encrypt your wallet?</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+12"/> <location line="+58"/> <source>Wallet encrypted</source> <translation type="unfinished"></translation> </message> <message> - <location line="-138"/> + <location line="-152"/> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> + <location line="+16"/> <source>Enter the old passphrase and new passphrase for the wallet.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+54"/> + <location line="+50"/> + <source>Continue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> <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> - <location line="+4"/> + <location line="+5"/> <source>Wallet to be encrypted</source> <translation type="unfinished"></translation> </message> @@ -245,7 +256,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+15"/> <source>Your wallet is now encrypted. </source> <translation type="unfinished"></translation> </message> @@ -273,7 +284,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-49"/> + <location line="-53"/> <location line="+3"/> <location line="+15"/> <source>Wallet unlock failed</source> @@ -281,17 +292,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="-17"/> - <location line="+34"/> + <location line="+38"/> <source>The passphrase entered for the wallet decryption was incorrect.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-31"/> + <location line="-35"/> <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="+23"/> + <location line="+27"/> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished"></translation> </message> @@ -307,7 +318,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+45"/> + <location line="+46"/> <location line="+33"/> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished"></translation> @@ -334,7 +345,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+179"/> + <location line="+184"/> <source>Runaway exception</source> <translation type="unfinished"></translation> </message> @@ -357,7 +368,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+250"/> + <location filename="../bitcoingui.cpp" line="+252"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -417,7 +428,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+163"/> + <location line="+184"/> <source>&Minimize</source> <translation type="unfinished"></translation> </message> @@ -427,7 +438,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+417"/> + <location line="+418"/> <source>Network activity disabled.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"></translation> @@ -438,7 +449,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1199"/> + <location line="-1221"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -533,7 +544,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+121"/> + <location line="+142"/> <source>&File</source> <translation>&File</translation> </message> @@ -553,7 +564,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Tabs toolbar</translation> </message> <message> - <location line="+481"/> + <location line="+482"/> <source>Syncing Headers (%1%)…</source> <translation type="unfinished"></translation> </message> @@ -578,7 +589,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-857"/> + <location line="-879"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> @@ -593,12 +604,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+30"/> + <location line="+31"/> <source>&Command-line options</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+769"/> + <location line="+790"/> <source>Processed %n block(s) of transaction history.</source> <translation> <numerusform>Processed %n block of transaction history.</numerusform> @@ -646,7 +657,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Up to date</translation> </message> <message> - <location line="-842"/> + <location line="-864"/> <source>Ctrl+Q</source> <translation type="unfinished"></translation> </message> @@ -733,7 +744,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished"></translation> </message> @@ -748,17 +759,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> - <source>default wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+21"/> + <location line="+51"/> + <location line="+59"/> <source>No wallets available</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="-53"/> <source>Wallet Data</source> <extracomment>Name of the wallet data file format.</extracomment> <translation type="unfinished"></translation> @@ -782,7 +789,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+69"/> + <location line="+90"/> <source>&Window</source> <translation type="unfinished">&Window</translation> </message> @@ -817,7 +824,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+117"/> + <location line="+118"/> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> @@ -1034,7 +1041,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Confirmed</translation> </message> <message> - <location filename="../coincontroldialog.cpp" line="+69"/> + <location filename="../coincontroldialog.cpp" line="+65"/> <source>Copy amount</source> <translation type="unfinished"></translation> </message> @@ -1094,7 +1101,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+298"/> + <location line="+294"/> <source>(%1 locked)</source> <translation type="unfinished"></translation> </message> @@ -1123,7 +1130,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>CreateWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+246"/> + <location filename="../walletcontroller.cpp" line="+248"/> <source>Create Wallet</source> <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment> <translation type="unfinished"></translation> @@ -1228,7 +1235,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../createwalletdialog.cpp" line="+22"/> + <location filename="../createwalletdialog.cpp" line="+20"/> <source>Create</source> <translation type="unfinished"></translation> </message> @@ -1310,7 +1317,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>FreespaceChecker</name> <message> - <location filename="../intro.cpp" line="+75"/> + <location filename="../intro.cpp" line="+73"/> <source>A new data directory will be created.</source> <translation>A new data directory will be created.</translation> </message> @@ -1338,7 +1345,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>HelpMessageDialog</name> <message> - <location filename="../utilitydialog.cpp" line="+38"/> + <location filename="../utilitydialog.cpp" line="+36"/> <source>version</source> <translation type="unfinished">version</translation> </message> @@ -1521,7 +1528,7 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+17"/> <source>Migrate Wallet</source> <translation type="unfinished"></translation> </message> @@ -1581,7 +1588,7 @@ The migration process will create a backup of the wallet before migrating. This <message> <location line="+7"/> <location line="+26"/> - <location filename="../modaloverlay.cpp" line="+152"/> + <location filename="../modaloverlay.cpp" line="+160"/> <source>Unknown…</source> <translation type="unfinished"></translation> </message> @@ -1622,12 +1629,12 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished"></translation> </message> <message> - <location filename="../modaloverlay.cpp" line="-121"/> + <location filename="../modaloverlay.cpp" line="-126"/> <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"></translation> </message> <message> - <location line="+127"/> + <location line="+132"/> <source>Unknown. Syncing Headers (%1, %2%)…</source> <translation type="unfinished"></translation> </message> @@ -1659,7 +1666,7 @@ The migration process will create a backup of the wallet before migrating. This <context> <name>OpenWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="-161"/> + <location filename="../walletcontroller.cpp" line="-155"/> <source>Open wallet failed</source> <translation type="unfinished"></translation> </message> @@ -1669,12 +1676,7 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> - <source>default wallet</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+4"/> + <location line="+14"/> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished"></translation> @@ -2059,7 +2061,7 @@ The migration process will create a backup of the wallet before migrating. This <translation>&Cancel</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+152"/> + <location filename="../optionsdialog.cpp" line="+153"/> <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> @@ -2145,7 +2147,7 @@ The migration process will create a backup of the wallet before migrating. This <context> <name>OptionsModel</name> <message> - <location filename="../optionsmodel.cpp" line="+230"/> + <location filename="../optionsmodel.cpp" line="+228"/> <source>Could not read setting "%1", %2.</source> <translation type="unfinished"></translation> </message> @@ -2282,7 +2284,7 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished"></translation> </message> <message> - <location filename="../psbtoperationsdialog.cpp" line="+60"/> + <location filename="../psbtoperationsdialog.cpp" line="+64"/> <source>Failed to load transaction: %1</source> <translation type="unfinished"></translation> </message> @@ -2421,7 +2423,7 @@ The migration process will create a backup of the wallet before migrating. This <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+149"/> + <location filename="../paymentserver.cpp" line="+145"/> <source>Payment request error</source> <translation type="unfinished"></translation> </message> @@ -2545,12 +2547,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+133"/> + <location filename="../guiutil.cpp" line="+138"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+288"/> + <location line="+295"/> <source>Ctrl+W</source> <translation type="unfinished"></translation> </message> @@ -2737,13 +2739,14 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <location line="+2"/> - <location filename="../rpcconsole.cpp" line="+1006"/> + <location filename="../rpcconsole.cpp" line="+1021"/> <source>%1 kB</source> <translation type="unfinished"></translation> </message> <message> <location line="+2"/> - <location filename="../rpcconsole.cpp" line="+2"/> + <location filename="../rpcconsole.cpp" line="+1"/> + <location line="+1"/> <source>%1 MB</source> <translation type="unfinished"></translation> </message> @@ -2753,7 +2756,12 @@ 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="-282"/> + <location line="+180"/> + <source>default wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../bitcoin.cpp" line="-287"/> <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> @@ -2765,7 +2773,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+423"/> + <location line="+428"/> <source>Error: %1</source> <translation type="unfinished"></translation> </message> @@ -2780,7 +2788,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location filename="../optionsdialog.cpp" line="-389"/> + <location filename="../optionsdialog.cpp" line="-391"/> <source>Embedded "%1"</source> <translation type="unfinished"></translation> </message> @@ -2798,7 +2806,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <context> <name>QRImageWidget</name> <message> - <location filename="../qrimagewidget.cpp" line="+30"/> + <location filename="../qrimagewidget.cpp" line="+28"/> <source>&Save Image…</source> <translation type="unfinished"></translation> </message> @@ -2844,11 +2852,11 @@ If you are receiving this error you should request the merchant provide a BIP21 <location line="+26"/> <location line="+36"/> <location line="+23"/> - <location line="+36"/> + <location line="+71"/> <location line="+23"/> <location line="+36"/> <location line="+23"/> - <location line="+692"/> + <location line="+767"/> <location line="+26"/> <location line="+26"/> <location line="+26"/> @@ -2876,12 +2884,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <location line="+26"/> <location line="+26"/> <location line="+26"/> - <location filename="../rpcconsole.h" line="+147"/> + <location filename="../rpcconsole.h" line="+145"/> <source>N/A</source> <translation>N/A</translation> </message> <message> - <location line="-1649"/> + <location line="-1759"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -2922,12 +2930,12 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <location line="+29"/> - <location line="+944"/> + <location line="+1054"/> <source>Network</source> <translation>Network</translation> </message> <message> - <location line="-937"/> + <location line="-1047"/> <source>Name</source> <translation type="unfinished"></translation> </message> @@ -2937,7 +2945,17 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation>Number of connections</translation> </message> <message> - <location line="+29"/> + <location line="+23"/> + <source>Local Addresses</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+28"/> + <source>Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> <source>Block chain</source> <translation>Block chain</translation> </message> @@ -2973,18 +2991,18 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <location line="+80"/> - <location line="+760"/> + <location line="+835"/> <source>Received</source> <translation type="unfinished"></translation> </message> <message> - <location line="-680"/> - <location line="+657"/> + <location line="-755"/> + <location line="+732"/> <source>Sent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-616"/> + <location line="-691"/> <source>&Peers</source> <translation type="unfinished"></translation> </message> @@ -2994,28 +3012,33 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+68"/> - <location filename="../rpcconsole.cpp" line="+165"/> + <location line="+76"/> + <location filename="../rpcconsole.cpp" line="+166"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+80"/> - <source>The transport layer version: %1</source> + <location line="+52"/> + <source>Hide Peers Detail</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <source>Transport</source> + <location line="+21"/> + <source>Ctrl+X</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> - <source>The BIP324 session ID string in hex, if any.</source> + <location line="+74"/> + <source>The transport layer version: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+3"/> + <source>Transport</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+26"/> <source>Session ID</source> <translation type="unfinished"></translation> </message> @@ -3101,18 +3124,18 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-1616"/> - <location line="+1103"/> + <location line="-1726"/> + <location line="+1213"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1177"/> + <location line="-1287"/> <source>Node window</source> <translation type="unfinished"></translation> </message> <message> - <location line="+253"/> + <location line="+288"/> <source>Current block height</source> <translation type="unfinished"></translation> </message> @@ -3132,7 +3155,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+546"/> + <location line="+621"/> <source>Permissions</source> <translation type="unfinished"></translation> </message> @@ -3147,7 +3170,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+75"/> + <location line="+49"/> + <source>The BIP324 session ID string in hex.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+26"/> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished"></translation> </message> @@ -3223,7 +3251,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-1310"/> + <location line="-1385"/> <source>Last block time</source> <translation>Last block time</translation> </message> @@ -3248,7 +3276,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-203"/> + <location filename="../rpcconsole.cpp" line="-216"/> <source>In:</source> <translation type="unfinished"></translation> </message> @@ -3298,7 +3326,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-475"/> + <location filename="../rpcconsole.cpp" line="-477"/> <source>Inbound: initiated by peer</source> <extracomment>Explanatory text for an inbound peer connection.</extracomment> <translation type="unfinished"></translation> @@ -3391,7 +3419,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+153"/> + <location line="+154"/> <source>&Copy address</source> <extracomment>Context menu action to copy the address of a peer.</extracomment> <translation type="unfinished"></translation> @@ -3433,17 +3461,22 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+230"/> + <location line="+231"/> <source>Network activity disabled</source> <translation type="unfinished"></translation> </message> <message> + <location line="+13"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+79"/> <source>Executing command without any wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="+325"/> + <location line="+326"/> <source>Ctrl+I</source> <translation type="unfinished"></translation> </message> @@ -3468,12 +3501,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-348"/> + <location line="-349"/> <source>Executing command using "%1" wallet</source> <translation type="unfinished"></translation> </message> <message> - <location line="-147"/> + <location line="-161"/> <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. @@ -3485,7 +3518,7 @@ For more information on using this console, type %6. <translation type="unfinished"></translation> </message> <message> - <location line="+157"/> + <location line="+171"/> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished"></translation> @@ -3728,7 +3761,7 @@ For more information on using this console, type %6. <translation type="unfinished"></translation> </message> <message> - <location filename="../receiverequestdialog.cpp" line="+48"/> + <location filename="../receiverequestdialog.cpp" line="+46"/> <source>Request payment to %1</source> <translation type="unfinished"></translation> </message> @@ -3741,7 +3774,7 @@ For more information on using this console, type %6. <context> <name>RecentRequestsTableModel</name> <message> - <location filename="../recentrequeststablemodel.cpp" line="+32"/> + <location filename="../recentrequeststablemodel.cpp" line="+34"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -3813,7 +3846,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="+762"/> + <location filename="../sendcoinsdialog.cpp" line="+763"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -3995,7 +4028,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-667"/> + <location filename="../sendcoinsdialog.cpp" line="-668"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -4072,7 +4105,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+62"/> + <location line="+63"/> <source>Sign failed</source> <translation type="unfinished"></translation> </message> @@ -4111,7 +4144,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="-324"/> + <location line="-325"/> <source>or</source> <translation type="unfinished"></translation> </message> @@ -4184,7 +4217,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+29"/> + <location line="+30"/> <source>PSBT saved to disk</source> <translation type="unfinished"></translation> </message> @@ -4397,7 +4430,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </message> <message> <location line="+6"/> - <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> + <source>You can sign messages/agreements with your legacy (P2PKH) 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> @@ -4512,27 +4545,25 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location filename="../signverifymessagedialog.cpp" line="+119"/> + <location filename="../signverifymessagedialog.cpp" line="+120"/> <location line="+99"/> <source>The entered address is invalid.</source> <translation type="unfinished"></translation> </message> <message> <location line="-99"/> - <location line="+7"/> - <location line="+93"/> - <location line="+7"/> + <location line="+100"/> <source>Please check the address and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> - <location line="+99"/> - <source>The entered address does not refer to a key.</source> + <location line="-93"/> + <location line="+98"/> + <source>The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-91"/> + <location line="-90"/> <source>Wallet unlock was cancelled.</source> <translation type="unfinished"></translation> </message> @@ -4557,7 +4588,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+69"/> + <location line="+66"/> <source>The signature could not be decoded.</source> <translation type="unfinished"></translation> </message> @@ -4578,7 +4609,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="-32"/> + <location line="-29"/> <source>Message verified.</source> <translation type="unfinished"></translation> </message> @@ -4586,7 +4617,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>SplashScreen</name> <message> - <location filename="../splashscreen.cpp" line="+177"/> + <location filename="../splashscreen.cpp" line="+175"/> <source>(press q to shutdown and continue later)</source> <translation type="unfinished"></translation> </message> @@ -4607,7 +4638,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>TransactionDesc</name> <message> - <location filename="../transactiondesc.cpp" line="+44"/> + <location filename="../transactiondesc.cpp" line="+40"/> <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"></translation> @@ -5170,7 +5201,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="-346"/> + <location filename="../walletcontroller.cpp" line="-347"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> @@ -5245,21 +5276,21 @@ Go to File > Open Wallet to load a wallet. <context> <name>WalletModel</name> <message> - <location filename="../walletmodel.cpp" line="+227"/> + <location filename="../walletmodel.cpp" line="+224"/> <location line="+13"/> <source>Send Coins</source> <translation type="unfinished">Send Coins</translation> </message> <message> <location line="+254"/> - <location line="+55"/> - <location line="+15"/> + <location line="+49"/> + <location line="+20"/> <location line="+5"/> <source>Fee bump error</source> <translation type="unfinished"></translation> </message> <message> - <location line="-75"/> + <location line="-74"/> <source>Increasing transaction fee failed</source> <translation type="unfinished"></translation> </message> @@ -5295,7 +5326,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+17"/> <source>Can't draft transaction.</source> <translation type="unfinished"></translation> </message> @@ -5306,12 +5337,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+0"/> - <source>Copied to clipboard</source> - <comment>Fee-bump PSBT saved</comment> + <source>Fee-bump PSBT copied to clipboard</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+13"/> <source>Can't sign transaction.</source> <translation type="unfinished"></translation> </message> @@ -5321,13 +5351,13 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> - <source>Can't display address</source> + <location line="+13"/> + <source>Signer error</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> - <source>default wallet</source> + <location line="+3"/> + <source>Can't display address</source> <translation type="unfinished"></translation> </message> </context> @@ -5463,17 +5493,17 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+12"/> + <location line="+15"/> <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"></translation> </message> <message> - <location line="+9"/> + <location line="+14"/> <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"></translation> </message> <message> - <location line="+4"/> + <location line="+8"/> <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> <translation type="unfinished"></translation> </message> @@ -5494,11 +5524,6 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+16"/> - <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"></translation> - </message> - <message> - <location line="+3"/> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation type="unfinished"></translation> </message> @@ -5518,7 +5543,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>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.</source> <translation type="unfinished"></translation> </message> @@ -5533,7 +5558,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+12"/> + <location line="+16"/> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation type="unfinished"></translation> </message> @@ -5623,7 +5648,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+19"/> <source>%s is set very high!</source> <translation type="unfinished"></translation> </message> @@ -5633,12 +5658,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> + <location line="+4"/> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished"></translation> </message> @@ -5658,7 +5678,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="-225"/> + <location line="-252"/> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> <translation type="unfinished"></translation> </message> @@ -5699,6 +5719,12 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+3"/> + <source>Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished"></translation> </message> @@ -5709,6 +5735,16 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+6"/> + <source>Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> <translation type="unfinished"></translation> </message> @@ -5718,7 +5754,17 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+7"/> + <source>Maximum transaction weight is less than transaction weight without inputs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Maximum transaction weight is too low, can not accommodate change output</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> <translation type="unfinished"></translation> </message> @@ -5738,7 +5784,17 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+29"/> + <location line="+14"/> + <source>Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source>The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> <translation type="unfinished"></translation> </message> @@ -5781,6 +5837,11 @@ Please try running the latest software version. </message> <message> <location line="+34"/> + <source>Your computer's date and time appear to be more than %d minutes out of sync with the network, this may lead to consensus failure. After you've confirmed your computer's clock, this message should no longer appear when you restart your node. Without a restart, it should stop showing automatically after you've connected to a sufficient number of new outbound peers, which may take some time. You can inspect the `timeoffset` field of the `getpeerinfo` and `getnetworkinfo` RPC methods to get more info.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> <source> Unable to cleanup failed migration</source> <translation type="unfinished"></translation> @@ -5792,7 +5853,22 @@ Unable to restore backup of wallet.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+3"/> + <source>whitebind may only be used for incoming connections ("out" was passed)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>A fatal internal error occurred, see debug.log for details: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Assumeutxo data not found for the given blockhash '%s'.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Block verification was interrupted</source> <translation type="unfinished"></translation> </message> @@ -5808,6 +5884,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Corrupt block found indicating potential hardware failure.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Corrupted block database detected</source> <translation type="unfinished"></translation> </message> @@ -5843,6 +5924,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error committing db txn for wallet transactions removal</source> <translation type="unfinished"></translation> </message> @@ -6028,11 +6114,26 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Failed to connect best block (%s).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Failed to disconnect block.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished"></translation> </message> <message> <location line="+1"/> + <source>Failed to read block.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished"></translation> </message> @@ -6048,6 +6149,26 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Failed to write block.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Failed to write to block index database.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Failed to write to coin database.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Failed to write undo data.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Failure removing transaction: %s</source> <translation type="unfinished"></translation> </message> @@ -6168,6 +6289,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Maximum transaction weight must be between %d and %d</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Missing amount</source> <translation type="unfinished"></translation> </message> @@ -6203,6 +6329,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Only direction was set, no permissions: '%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> @@ -6258,6 +6389,21 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+3"/> + <source>Signer did not echo address</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Signer echoed unexpected address %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Signer returned error: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Signing transaction failed</source> <translation type="unfinished"></translation> </message> @@ -6293,6 +6439,21 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>System error while flushing: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>System error while loading external block file: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>System error while saving block to disk: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>The source code is available from %s.</source> <translation type="unfinished"></translation> </message> @@ -6313,6 +6474,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>There is no ScriptPubKeyManager for this address</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>This is experimental software.</source> <translation type="unfinished"></translation> </message> @@ -6363,11 +6529,6 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> - <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished"></translation> </message> @@ -6443,6 +6604,11 @@ Unable to restore backup of wallet.</source> </message> <message> <location line="+1"/> + <source>Unrecognised option "%s" provided in -test=<option>.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> <translation type="unfinished"></translation> </message> @@ -6462,7 +6628,7 @@ Unable to restore backup of wallet.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-110"/> + <location line="-126"/> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> <translation type="unfinished"></translation> </message> @@ -6472,7 +6638,7 @@ Unable to restore backup of wallet.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+110"/> + <location line="+126"/> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished"></translation> </message> @@ -6492,7 +6658,7 @@ Unable to restore backup of wallet.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-45"/> + <location line="-52"/> <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 2bab80e3dd..eef3fd3cfe 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">&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">117</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../addressbookpage.cpp</context><context context-type="linenumber">113</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">87</context></context-group> + <context-group purpose="location"><context context-type="linenumber">83</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">88</context></context-group> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> </trans-unit> <trans-unit id="_msg14"> <source xml:space="preserve">C&hoose</source> - <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + <context-group purpose="location"><context context-type="linenumber">89</context></context-group> </trans-unit> <trans-unit id="_msg15"> <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">99</context></context-group> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> <trans-unit id="_msg16"> <source xml:space="preserve">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> - <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="_msg17"> <source xml:space="preserve">&Copy Address</source> - <context-group purpose="location"><context context-type="linenumber">112</context></context-group> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> <trans-unit id="_msg18"> <source xml:space="preserve">Copy &Label</source> - <context-group purpose="location"><context context-type="linenumber">113</context></context-group> + <context-group purpose="location"><context context-type="linenumber">109</context></context-group> </trans-unit> <trans-unit id="_msg19"> <source xml:space="preserve">&Edit</source> - <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> <trans-unit id="_msg20"> <source xml:space="preserve">Export Address List</source> - <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> <trans-unit id="_msg21"> <source xml:space="preserve">Comma separated file</source> - <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + <context-group purpose="location"><context context-type="linenumber">278</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="_msg22"> <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">298</context></context-group> + <context-group purpose="location"><context context-type="linenumber">294</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="_msg23"> <source xml:space="preserve">Sending addresses - %1</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="_msg24"> <source xml:space="preserve">Receiving addresses - %1</source> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> </trans-unit> <trans-unit id="_msg25"> <source xml:space="preserve">Exporting Failed</source> - <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + <context-group purpose="location"><context context-type="linenumber">291</context></context-group> </trans-unit> </group> </body></file> @@ -156,122 +156,131 @@ Signing is only possible with addresses of the type 'legacy'.</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">49</context></context-group> + <context-group purpose="location"><context context-type="linenumber">45</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">52</context></context-group> + <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> <trans-unit id="_msg36"> <source xml:space="preserve">Unlock wallet</source> - <context-group purpose="location"><context context-type="linenumber">57</context></context-group> + <context-group purpose="location"><context context-type="linenumber">54</context></context-group> </trans-unit> <trans-unit id="_msg37"> <source xml:space="preserve">Change passphrase</source> - <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + <context-group purpose="location"><context context-type="linenumber">57</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">107</context></context-group> + <context-group purpose="location"><context context-type="linenumber">105</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 <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">106</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">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">106</context></context-group> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> <trans-unit id="_msg41"> <source xml:space="preserve">Wallet encrypted</source> - <context-group purpose="location"><context context-type="linenumber">126</context></context-group> - <context-group purpose="location"><context context-type="linenumber">184</context></context-group> + <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> </trans-unit> <trans-unit id="_msg42"> <source xml:space="preserve">Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + <context-group purpose="location"><context context-type="linenumber">42</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">61</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</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">115</context></context-group> + <source xml:space="preserve">Continue</source> + <context-group purpose="location"><context context-type="linenumber">108</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">119</context></context-group> + <source xml:space="preserve">Back</source> + <context-group purpose="location"><context context-type="linenumber">109</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">121</context></context-group> + <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">116</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">128</context></context-group> + <source xml:space="preserve">Wallet to be encrypted</source> + <context-group purpose="location"><context context-type="linenumber">121</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">130</context></context-group> + <source xml:space="preserve">Your wallet is about to be encrypted. </source> + <context-group purpose="location"><context context-type="linenumber">123</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">136</context></context-group> - <context-group purpose="location"><context context-type="linenumber">144</context></context-group> - <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + <source xml:space="preserve">Your wallet is now encrypted. </source> + <context-group purpose="location"><context context-type="linenumber">138</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">137</context></context-group> + <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">140</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">145</context></context-group> - <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + <source xml:space="preserve">Wallet encryption failed</source> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + <context-group purpose="location"><context context-type="linenumber">154</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</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">158</context></context-group> - <context-group purpose="location"><context context-type="linenumber">161</context></context-group> - <context-group purpose="location"><context context-type="linenumber">176</context></context-group> + <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">147</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">159</context></context-group> - <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + <source xml:space="preserve">The supplied passphrases do not match.</source> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> <trans-unit id="_msg54"> - <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> + <source xml:space="preserve">Wallet unlock failed</source> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + <context-group purpose="location"><context context-type="linenumber">167</context></context-group> + <context-group purpose="location"><context context-type="linenumber">182</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">185</context></context-group> + <source xml:space="preserve">The passphrase entered for the wallet decryption was incorrect.</source> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + <context-group purpose="location"><context context-type="linenumber">203</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">192</context></context-group> - <context-group purpose="location"><context context-type="linenumber">195</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">168</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">196</context></context-group> + <source xml:space="preserve">Wallet passphrase was successfully changed.</source> + <context-group purpose="location"><context context-type="linenumber">195</context></context-group> </trans-unit> <trans-unit id="_msg58"> + <source xml:space="preserve">Passphrase change failed</source> + <context-group purpose="location"><context context-type="linenumber">202</context></context-group> + <context-group purpose="location"><context context-type="linenumber">205</context></context-group> + </trans-unit> + <trans-unit id="_msg59"> + <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">206</context></context-group> + </trans-unit> + <trans-unit id="_msg60"> <source xml:space="preserve">Warning: The Caps Lock key is on!</source> - <context-group purpose="location"><context context-type="linenumber">241</context></context-group> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">285</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="_msg59"> + <trans-unit id="_msg61"> <source xml:space="preserve">IP/Netmask</source> <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> - <trans-unit id="_msg60"> + <trans-unit id="_msg62"> <source xml:space="preserve">Banned Until</source> <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> @@ -279,605 +288,602 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../bitcoin.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="BitcoinApplication"> - <trans-unit id="_msg61"> + <trans-unit id="_msg63"> <source xml:space="preserve">Settings file %1 might be corrupt or invalid.</source> <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> - <trans-unit id="_msg62"> + <trans-unit id="_msg64"> <source xml:space="preserve">Runaway exception</source> - <context-group purpose="location"><context context-type="linenumber">454</context></context-group> + <context-group purpose="location"><context context-type="linenumber">459</context></context-group> </trans-unit> - <trans-unit id="_msg63"> + <trans-unit id="_msg65"> <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">455</context></context-group> + <context-group purpose="location"><context context-type="linenumber">460</context></context-group> </trans-unit> - <trans-unit id="_msg64"> + <trans-unit id="_msg66"> <source xml:space="preserve">Internal error</source> - <context-group purpose="location"><context context-type="linenumber">464</context></context-group> + <context-group purpose="location"><context context-type="linenumber">469</context></context-group> </trans-unit> - <trans-unit id="_msg65"> + <trans-unit id="_msg67"> <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">465</context></context-group> + <context-group purpose="location"><context context-type="linenumber">470</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg66"> + <trans-unit id="_msg68"> <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> <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="_msg67"> + <trans-unit id="_msg69"> <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">203</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="_msg68"> + <trans-unit id="_msg70"> <source xml:space="preserve">Error: %1</source> - <context-group purpose="location"><context context-type="linenumber">626</context></context-group> + <context-group purpose="location"><context context-type="linenumber">631</context></context-group> </trans-unit> - <trans-unit id="_msg69"> + <trans-unit id="_msg71"> <source xml:space="preserve">%1 didn't yet exit safely…</source> - <context-group purpose="location"><context context-type="linenumber">699</context></context-group> + <context-group purpose="location"><context context-type="linenumber">704</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="_msg70"> + <trans-unit id="_msg72"> <source xml:space="preserve">&Overview</source> - <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> </trans-unit> - <trans-unit id="_msg71"> + <trans-unit id="_msg73"> <source xml:space="preserve">Show general overview of wallet</source> - <context-group purpose="location"><context context-type="linenumber">251</context></context-group> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg72"> + <trans-unit id="_msg74"> <source xml:space="preserve">&Transactions</source> - <context-group purpose="location"><context context-type="linenumber">271</context></context-group> + <context-group purpose="location"><context context-type="linenumber">273</context></context-group> </trans-unit> - <trans-unit id="_msg73"> + <trans-unit id="_msg75"> <source xml:space="preserve">Browse transaction history</source> - <context-group purpose="location"><context context-type="linenumber">272</context></context-group> + <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> - <trans-unit id="_msg74"> + <trans-unit id="_msg76"> <source xml:space="preserve">E&xit</source> - <context-group purpose="location"><context context-type="linenumber">291</context></context-group> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> - <trans-unit id="_msg75"> + <trans-unit id="_msg77"> <source xml:space="preserve">Quit application</source> - <context-group purpose="location"><context context-type="linenumber">292</context></context-group> + <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> - <trans-unit id="_msg76"> + <trans-unit id="_msg78"> <source xml:space="preserve">&About %1</source> - <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + <context-group purpose="location"><context context-type="linenumber">297</context></context-group> </trans-unit> - <trans-unit id="_msg77"> + <trans-unit id="_msg79"> <source xml:space="preserve">Show information about %1</source> - <context-group purpose="location"><context context-type="linenumber">296</context></context-group> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> - <trans-unit id="_msg78"> + <trans-unit id="_msg80"> <source xml:space="preserve">About &Qt</source> - <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg79"> + <trans-unit id="_msg81"> <source xml:space="preserve">Show information about Qt</source> - <context-group purpose="location"><context context-type="linenumber">300</context></context-group> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> - <trans-unit id="_msg80"> + <trans-unit id="_msg82"> <source xml:space="preserve">Modify configuration options for %1</source> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg81"> + <trans-unit id="_msg83"> <source xml:space="preserve">Create a new wallet</source> - <context-group purpose="location"><context context-type="linenumber">347</context></context-group> + <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg82"> + <trans-unit id="_msg84"> <source xml:space="preserve">&Minimize</source> - <context-group purpose="location"><context context-type="linenumber">510</context></context-group> + <context-group purpose="location"><context context-type="linenumber">533</context></context-group> </trans-unit> - <trans-unit id="_msg83"> + <trans-unit id="_msg85"> <source xml:space="preserve">Wallet:</source> - <context-group purpose="location"><context context-type="linenumber">589</context></context-group> + <context-group purpose="location"><context context-type="linenumber">612</context></context-group> </trans-unit> - <trans-unit id="_msg84"> + <trans-unit id="_msg86"> <source xml:space="preserve">Network activity disabled.</source> - <context-group purpose="location"><context context-type="linenumber">1006</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1030</context></context-group> <note annotates="source" from="developer">A substring of the tooltip.</note> </trans-unit> - <trans-unit id="_msg85"> + <trans-unit id="_msg87"> <source xml:space="preserve">Proxy is <b>enabled</b>: %1</source> - <context-group purpose="location"><context context-type="linenumber">1457</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1481</context></context-group> </trans-unit> - <trans-unit id="_msg86"> + <trans-unit id="_msg88"> <source xml:space="preserve">Send coins to a Bitcoin address</source> - <context-group purpose="location"><context context-type="linenumber">258</context></context-group> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg87"> + <trans-unit id="_msg89"> <source xml:space="preserve">Backup wallet to another location</source> - <context-group purpose="location"><context context-type="linenumber">311</context></context-group> - </trans-unit> - <trans-unit id="_msg88"> - <source xml:space="preserve">Change the passphrase used for wallet encryption</source> <context-group purpose="location"><context context-type="linenumber">313</context></context-group> </trans-unit> - <trans-unit id="_msg89"> - <source xml:space="preserve">&Send</source> - <context-group purpose="location"><context context-type="linenumber">257</context></context-group> - </trans-unit> <trans-unit id="_msg90"> - <source xml:space="preserve">&Receive</source> - <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <source xml:space="preserve">Change the passphrase used for wallet encryption</source> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> </trans-unit> <trans-unit id="_msg91"> - <source xml:space="preserve">&Options…</source> - <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + <source xml:space="preserve">&Send</source> + <context-group purpose="location"><context context-type="linenumber">259</context></context-group> </trans-unit> <trans-unit id="_msg92"> - <source xml:space="preserve">&Encrypt Wallet…</source> - <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + <source xml:space="preserve">&Receive</source> + <context-group purpose="location"><context context-type="linenumber">266</context></context-group> </trans-unit> <trans-unit id="_msg93"> - <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <source xml:space="preserve">&Options…</source> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> <trans-unit id="_msg94"> - <source xml:space="preserve">&Backup Wallet…</source> - <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + <source xml:space="preserve">&Encrypt Wallet…</source> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> <trans-unit id="_msg95"> - <source xml:space="preserve">&Change Passphrase…</source> - <context-group purpose="location"><context context-type="linenumber">312</context></context-group> + <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> <trans-unit id="_msg96"> - <source xml:space="preserve">Sign &message…</source> - <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + <source xml:space="preserve">&Backup Wallet…</source> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> </trans-unit> <trans-unit id="_msg97"> - <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source> - <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + <source xml:space="preserve">&Change Passphrase…</source> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> <trans-unit id="_msg98"> - <source xml:space="preserve">&Verify message…</source> + <source xml:space="preserve">Sign &message…</source> <context-group purpose="location"><context context-type="linenumber">316</context></context-group> </trans-unit> <trans-unit id="_msg99"> - <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source> <context-group purpose="location"><context context-type="linenumber">317</context></context-group> </trans-unit> <trans-unit id="_msg100"> - <source xml:space="preserve">&Load PSBT from file…</source> + <source xml:space="preserve">&Verify message…</source> <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> <trans-unit id="_msg101"> - <source xml:space="preserve">Open &URI…</source> - <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> <trans-unit id="_msg102"> - <source xml:space="preserve">Close Wallet…</source> - <context-group purpose="location"><context context-type="linenumber">342</context></context-group> + <source xml:space="preserve">&Load PSBT from file…</source> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> </trans-unit> <trans-unit id="_msg103"> - <source xml:space="preserve">Create Wallet…</source> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <source xml:space="preserve">Open &URI…</source> + <context-group purpose="location"><context context-type="linenumber">336</context></context-group> </trans-unit> <trans-unit id="_msg104"> - <source xml:space="preserve">Close All Wallets…</source> - <context-group purpose="location"><context context-type="linenumber">355</context></context-group> + <source xml:space="preserve">Close Wallet…</source> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> <trans-unit id="_msg105"> - <source xml:space="preserve">&File</source> - <context-group purpose="location"><context context-type="linenumber">476</context></context-group> + <source xml:space="preserve">Create Wallet…</source> + <context-group purpose="location"><context context-type="linenumber">347</context></context-group> </trans-unit> <trans-unit id="_msg106"> - <source xml:space="preserve">&Settings</source> - <context-group purpose="location"><context context-type="linenumber">497</context></context-group> + <source xml:space="preserve">Close All Wallets…</source> + <context-group purpose="location"><context context-type="linenumber">357</context></context-group> </trans-unit> <trans-unit id="_msg107"> - <source xml:space="preserve">&Help</source> - <context-group purpose="location"><context context-type="linenumber">558</context></context-group> + <source xml:space="preserve">&File</source> + <context-group purpose="location"><context context-type="linenumber">499</context></context-group> </trans-unit> <trans-unit id="_msg108"> - <source xml:space="preserve">Tabs toolbar</source> - <context-group purpose="location"><context context-type="linenumber">569</context></context-group> + <source xml:space="preserve">&Settings</source> + <context-group purpose="location"><context context-type="linenumber">520</context></context-group> </trans-unit> <trans-unit id="_msg109"> - <source xml:space="preserve">Syncing Headers (%1%)…</source> - <context-group purpose="location"><context context-type="linenumber">1050</context></context-group> + <source xml:space="preserve">&Help</source> + <context-group purpose="location"><context context-type="linenumber">581</context></context-group> </trans-unit> <trans-unit id="_msg110"> - <source xml:space="preserve">Synchronizing with network…</source> - <context-group purpose="location"><context context-type="linenumber">1108</context></context-group> + <source xml:space="preserve">Tabs toolbar</source> + <context-group purpose="location"><context context-type="linenumber">592</context></context-group> </trans-unit> <trans-unit id="_msg111"> - <source xml:space="preserve">Indexing blocks on disk…</source> - <context-group purpose="location"><context context-type="linenumber">1113</context></context-group> + <source xml:space="preserve">Syncing Headers (%1%)…</source> + <context-group purpose="location"><context context-type="linenumber">1074</context></context-group> </trans-unit> <trans-unit id="_msg112"> - <source xml:space="preserve">Processing blocks on disk…</source> - <context-group purpose="location"><context context-type="linenumber">1115</context></context-group> + <source xml:space="preserve">Synchronizing with network…</source> + <context-group purpose="location"><context context-type="linenumber">1132</context></context-group> </trans-unit> <trans-unit id="_msg113"> - <source xml:space="preserve">Connecting to peers…</source> - <context-group purpose="location"><context context-type="linenumber">1122</context></context-group> + <source xml:space="preserve">Indexing blocks on disk…</source> + <context-group purpose="location"><context context-type="linenumber">1137</context></context-group> </trans-unit> <trans-unit id="_msg114"> - <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source> - <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + <source xml:space="preserve">Processing blocks on disk…</source> + <context-group purpose="location"><context context-type="linenumber">1139</context></context-group> </trans-unit> <trans-unit id="_msg115"> - <source xml:space="preserve">Show the list of used sending addresses and labels</source> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <source xml:space="preserve">Connecting to peers…</source> + <context-group purpose="location"><context context-type="linenumber">1146</context></context-group> </trans-unit> <trans-unit id="_msg116"> - <source xml:space="preserve">Show the list of used receiving addresses and labels</source> - <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source> + <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> <trans-unit id="_msg117"> + <source xml:space="preserve">Show the list of used sending addresses and labels</source> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + </trans-unit> + <trans-unit id="_msg118"> + <source xml:space="preserve">Show the list of used receiving addresses and labels</source> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + </trans-unit> + <trans-unit id="_msg119"> <source xml:space="preserve">&Command-line options</source> - <context-group purpose="location"><context context-type="linenumber">362</context></context-group> + <context-group purpose="location"><context context-type="linenumber">365</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">1131</context></context-group> - <trans-unit id="_msg118[0]"> + <context-group purpose="location"><context context-type="linenumber">1155</context></context-group> + <trans-unit id="_msg120[0]"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> </trans-unit> - <trans-unit id="_msg118[1]"> + <trans-unit id="_msg120[1]"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> </trans-unit> </group> - <trans-unit id="_msg119"> + <trans-unit id="_msg121"> <source xml:space="preserve">%1 behind</source> - <context-group purpose="location"><context context-type="linenumber">1154</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1178</context></context-group> </trans-unit> - <trans-unit id="_msg120"> + <trans-unit id="_msg122"> <source xml:space="preserve">Catching up…</source> - <context-group purpose="location"><context context-type="linenumber">1159</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1183</context></context-group> </trans-unit> - <trans-unit id="_msg121"> + <trans-unit id="_msg123"> <source xml:space="preserve">Last received block was generated %1 ago.</source> - <context-group purpose="location"><context context-type="linenumber">1178</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1202</context></context-group> </trans-unit> - <trans-unit id="_msg122"> + <trans-unit id="_msg124"> <source xml:space="preserve">Transactions after this will not yet be visible.</source> - <context-group purpose="location"><context context-type="linenumber">1180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1204</context></context-group> </trans-unit> - <trans-unit id="_msg123"> + <trans-unit id="_msg125"> <source xml:space="preserve">Error</source> - <context-group purpose="location"><context context-type="linenumber">1220</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1244</context></context-group> </trans-unit> - <trans-unit id="_msg124"> + <trans-unit id="_msg126"> <source xml:space="preserve">Warning</source> - <context-group purpose="location"><context context-type="linenumber">1224</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1248</context></context-group> </trans-unit> - <trans-unit id="_msg125"> + <trans-unit id="_msg127"> <source xml:space="preserve">Information</source> - <context-group purpose="location"><context context-type="linenumber">1228</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1252</context></context-group> </trans-unit> - <trans-unit id="_msg126"> + <trans-unit id="_msg128"> <source xml:space="preserve">Up to date</source> - <context-group purpose="location"><context context-type="linenumber">1135</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1159</context></context-group> </trans-unit> - <trans-unit id="_msg127"> + <trans-unit id="_msg129"> <source xml:space="preserve">Ctrl+Q</source> - <context-group purpose="location"><context context-type="linenumber">293</context></context-group> + <context-group purpose="location"><context context-type="linenumber">295</context></context-group> </trans-unit> - <trans-unit id="_msg128"> + <trans-unit id="_msg130"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg129"> + <trans-unit id="_msg131"> <source xml:space="preserve">Load PSBT from &clipboard…</source> - <context-group purpose="location"><context context-type="linenumber">320</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg130"> + <trans-unit id="_msg132"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg131"> + <trans-unit id="_msg133"> <source xml:space="preserve">Node window</source> - <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg132"> + <trans-unit id="_msg134"> <source xml:space="preserve">Open node debugging and diagnostic console</source> - <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg133"> + <trans-unit id="_msg135"> <source xml:space="preserve">&Sending addresses</source> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> </trans-unit> - <trans-unit id="_msg134"> + <trans-unit id="_msg136"> <source xml:space="preserve">&Receiving addresses</source> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg135"> + <trans-unit id="_msg137"> <source xml:space="preserve">Open a bitcoin: URI</source> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">337</context></context-group> </trans-unit> - <trans-unit id="_msg136"> + <trans-unit id="_msg138"> <source xml:space="preserve">Open Wallet</source> - <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> </trans-unit> - <trans-unit id="_msg137"> + <trans-unit id="_msg139"> <source xml:space="preserve">Open a wallet</source> - <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg138"> + <trans-unit id="_msg140"> <source xml:space="preserve">Close wallet</source> - <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">345</context></context-group> </trans-unit> - <trans-unit id="_msg139"> + <trans-unit id="_msg141"> <source xml:space="preserve">Restore Wallet…</source> - <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</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="_msg140"> + <trans-unit id="_msg142"> <source xml:space="preserve">Restore a wallet from a backup file</source> - <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + <context-group purpose="location"><context context-type="linenumber">355</context></context-group> <note annotates="source" from="developer">Status tip for Restore Wallet menu item</note> </trans-unit> - <trans-unit id="_msg141"> + <trans-unit id="_msg143"> <source xml:space="preserve">Close all wallets</source> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> - </trans-unit> - <trans-unit id="_msg142"> - <source xml:space="preserve">Migrate Wallet</source> <context-group purpose="location"><context context-type="linenumber">358</context></context-group> </trans-unit> - <trans-unit id="_msg143"> - <source xml:space="preserve">Migrate a wallet</source> - <context-group purpose="location"><context context-type="linenumber">360</context></context-group> - </trans-unit> <trans-unit id="_msg144"> - <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">364</context></context-group> + <source xml:space="preserve">Migrate Wallet</source> + <context-group purpose="location"><context context-type="linenumber">360</context></context-group> </trans-unit> <trans-unit id="_msg145"> - <source xml:space="preserve">&Mask values</source> - <context-group purpose="location"><context context-type="linenumber">366</context></context-group> + <source xml:space="preserve">Migrate a wallet</source> + <context-group purpose="location"><context context-type="linenumber">362</context></context-group> </trans-unit> <trans-unit id="_msg146"> - <source xml:space="preserve">Mask the values in the Overview tab</source> - <context-group purpose="location"><context context-type="linenumber">368</context></context-group> + <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">367</context></context-group> </trans-unit> <trans-unit id="_msg147"> - <source xml:space="preserve">default wallet</source> - <context-group purpose="location"><context context-type="linenumber">399</context></context-group> + <source xml:space="preserve">&Mask values</source> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> </trans-unit> <trans-unit id="_msg148"> - <source xml:space="preserve">No wallets available</source> - <context-group purpose="location"><context context-type="linenumber">420</context></context-group> + <source xml:space="preserve">Mask the values in the Overview tab</source> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> <trans-unit id="_msg149"> + <source xml:space="preserve">No wallets available</source> + <context-group purpose="location"><context context-type="linenumber">422</context></context-group> + <context-group purpose="location"><context context-type="linenumber">481</context></context-group> + </trans-unit> + <trans-unit id="_msg150"> <source xml:space="preserve">Wallet Data</source> - <context-group purpose="location"><context context-type="linenumber">426</context></context-group> + <context-group purpose="location"><context context-type="linenumber">428</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="_msg151"> <source xml:space="preserve">Load Wallet Backup</source> - <context-group purpose="location"><context context-type="linenumber">429</context></context-group> + <context-group purpose="location"><context context-type="linenumber">431</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="_msg152"> <source xml:space="preserve">Restore Wallet</source> - <context-group purpose="location"><context context-type="linenumber">437</context></context-group> + <context-group purpose="location"><context context-type="linenumber">439</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="_msg153"> <source xml:space="preserve">Wallet Name</source> - <context-group purpose="location"><context context-type="linenumber">439</context></context-group> + <context-group purpose="location"><context context-type="linenumber">441</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="_msg154"> <source xml:space="preserve">&Window</source> - <context-group purpose="location"><context context-type="linenumber">508</context></context-group> + <context-group purpose="location"><context context-type="linenumber">531</context></context-group> </trans-unit> - <trans-unit id="_msg154"> + <trans-unit id="_msg155"> <source xml:space="preserve">Ctrl+M</source> - <context-group purpose="location"><context context-type="linenumber">511</context></context-group> + <context-group purpose="location"><context context-type="linenumber">534</context></context-group> </trans-unit> - <trans-unit id="_msg155"> + <trans-unit id="_msg156"> <source xml:space="preserve">Zoom</source> - <context-group purpose="location"><context context-type="linenumber">520</context></context-group> + <context-group purpose="location"><context context-type="linenumber">543</context></context-group> </trans-unit> - <trans-unit id="_msg156"> + <trans-unit id="_msg157"> <source xml:space="preserve">Main Window</source> - <context-group purpose="location"><context context-type="linenumber">538</context></context-group> + <context-group purpose="location"><context context-type="linenumber">561</context></context-group> </trans-unit> - <trans-unit id="_msg157"> + <trans-unit id="_msg158"> <source xml:space="preserve">%1 client</source> - <context-group purpose="location"><context context-type="linenumber">817</context></context-group> + <context-group purpose="location"><context context-type="linenumber">840</context></context-group> </trans-unit> - <trans-unit id="_msg158"> + <trans-unit id="_msg159"> <source xml:space="preserve">&Hide</source> - <context-group purpose="location"><context context-type="linenumber">885</context></context-group> + <context-group purpose="location"><context context-type="linenumber">908</context></context-group> </trans-unit> - <trans-unit id="_msg159"> + <trans-unit id="_msg160"> <source xml:space="preserve">S&how</source> - <context-group purpose="location"><context context-type="linenumber">886</context></context-group> + <context-group purpose="location"><context context-type="linenumber">909</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">1003</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1027</context></context-group> <note annotates="source" from="developer">A substring of the tooltip.</note> - <trans-unit id="_msg160[0]"> + <trans-unit id="_msg161[0]"> <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> </trans-unit> - <trans-unit id="_msg160[1]"> + <trans-unit id="_msg161[1]"> <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> </trans-unit> </group> - <trans-unit id="_msg161"> + <trans-unit id="_msg162"> <source xml:space="preserve">Click for more actions.</source> - <context-group purpose="location"><context context-type="linenumber">1013</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1037</context></context-group> <note annotates="source" from="developer">A substring of the tooltip. "More actions" are available via the context menu.</note> </trans-unit> - <trans-unit id="_msg162"> + <trans-unit id="_msg163"> <source xml:space="preserve">Show Peers tab</source> - <context-group purpose="location"><context context-type="linenumber">1030</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1054</context></context-group> <note annotates="source" from="developer">A context menu item. The "Peers tab" is an element of the "Node window".</note> </trans-unit> - <trans-unit id="_msg163"> + <trans-unit id="_msg164"> <source xml:space="preserve">Disable network activity</source> - <context-group purpose="location"><context context-type="linenumber">1038</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1062</context></context-group> <note annotates="source" from="developer">A context menu item.</note> </trans-unit> - <trans-unit id="_msg164"> + <trans-unit id="_msg165"> <source xml:space="preserve">Enable network activity</source> - <context-group purpose="location"><context context-type="linenumber">1040</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1064</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="_msg166"> <source xml:space="preserve">Pre-syncing Headers (%1%)…</source> - <context-group purpose="location"><context context-type="linenumber">1057</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1081</context></context-group> </trans-unit> - <trans-unit id="_msg166"> + <trans-unit id="_msg167"> <source xml:space="preserve">Error creating wallet</source> - <context-group purpose="location"><context context-type="linenumber">1196</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1220</context></context-group> </trans-unit> - <trans-unit id="_msg167"> + <trans-unit id="_msg168"> <source xml:space="preserve">Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <context-group purpose="location"><context context-type="linenumber">1196</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1220</context></context-group> </trans-unit> - <trans-unit id="_msg168"> + <trans-unit id="_msg169"> <source xml:space="preserve">Error: %1</source> - <context-group purpose="location"><context context-type="linenumber">1221</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1245</context></context-group> </trans-unit> - <trans-unit id="_msg169"> + <trans-unit id="_msg170"> <source xml:space="preserve">Warning: %1</source> - <context-group purpose="location"><context context-type="linenumber">1225</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1249</context></context-group> </trans-unit> - <trans-unit id="_msg170"> + <trans-unit id="_msg171"> <source xml:space="preserve">Date: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1333</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1357</context></context-group> </trans-unit> - <trans-unit id="_msg171"> + <trans-unit id="_msg172"> <source xml:space="preserve">Amount: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1334</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1358</context></context-group> </trans-unit> - <trans-unit id="_msg172"> + <trans-unit id="_msg173"> <source xml:space="preserve">Wallet: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1336</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1360</context></context-group> </trans-unit> - <trans-unit id="_msg173"> + <trans-unit id="_msg174"> <source xml:space="preserve">Type: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1338</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1362</context></context-group> </trans-unit> - <trans-unit id="_msg174"> + <trans-unit id="_msg175"> <source xml:space="preserve">Label: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1340</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1364</context></context-group> </trans-unit> - <trans-unit id="_msg175"> + <trans-unit id="_msg176"> <source xml:space="preserve">Address: %1 </source> - <context-group purpose="location"><context context-type="linenumber">1342</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1366</context></context-group> </trans-unit> - <trans-unit id="_msg176"> + <trans-unit id="_msg177"> <source xml:space="preserve">Sent transaction</source> - <context-group purpose="location"><context context-type="linenumber">1343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1367</context></context-group> </trans-unit> - <trans-unit id="_msg177"> + <trans-unit id="_msg178"> <source xml:space="preserve">Incoming transaction</source> - <context-group purpose="location"><context context-type="linenumber">1343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1367</context></context-group> </trans-unit> - <trans-unit id="_msg178"> + <trans-unit id="_msg179"> <source xml:space="preserve">HD key generation is <b>enabled</b></source> - <context-group purpose="location"><context context-type="linenumber">1395</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1419</context></context-group> </trans-unit> - <trans-unit id="_msg179"> + <trans-unit id="_msg180"> <source xml:space="preserve">HD key generation is <b>disabled</b></source> - <context-group purpose="location"><context context-type="linenumber">1395</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1419</context></context-group> </trans-unit> - <trans-unit id="_msg180"> + <trans-unit id="_msg181"> <source xml:space="preserve">Private key <b>disabled</b></source> - <context-group purpose="location"><context context-type="linenumber">1395</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1419</context></context-group> </trans-unit> - <trans-unit id="_msg181"> + <trans-unit id="_msg182"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <context-group purpose="location"><context context-type="linenumber">1418</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1442</context></context-group> </trans-unit> - <trans-unit id="_msg182"> + <trans-unit id="_msg183"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <context-group purpose="location"><context context-type="linenumber">1426</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1450</context></context-group> </trans-unit> - <trans-unit id="_msg183"> + <trans-unit id="_msg184"> <source xml:space="preserve">Original message:</source> - <context-group purpose="location"><context context-type="linenumber">1545</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1569</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl"> - <trans-unit id="_msg184"> + <trans-unit id="_msg185"> <source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source> - <context-group purpose="location"><context context-type="linenumber">1584</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1608</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="_msg185"> + <trans-unit id="_msg186"> <source xml:space="preserve">Coin Selection</source> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg186"> + <trans-unit id="_msg187"> <source xml:space="preserve">Quantity:</source> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg187"> + <trans-unit id="_msg188"> <source xml:space="preserve">Bytes:</source> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg188"> + <trans-unit id="_msg189"> <source xml:space="preserve">Amount:</source> <context-group purpose="location"><context context-type="linenumber">125</context></context-group> </trans-unit> - <trans-unit id="_msg189"> + <trans-unit id="_msg190"> <source xml:space="preserve">Fee:</source> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg190"> + <trans-unit id="_msg191"> <source xml:space="preserve">After Fee:</source> <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg191"> + <trans-unit id="_msg192"> <source xml:space="preserve">Change:</source> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg192"> + <trans-unit id="_msg193"> <source xml:space="preserve">(un)select all</source> <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg193"> + <trans-unit id="_msg194"> <source xml:space="preserve">Tree mode</source> <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg194"> + <trans-unit id="_msg195"> <source xml:space="preserve">List mode</source> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg195"> + <trans-unit id="_msg196"> <source xml:space="preserve">Amount</source> <context-group purpose="location"><context context-type="linenumber">391</context></context-group> </trans-unit> - <trans-unit id="_msg196"> + <trans-unit id="_msg197"> <source xml:space="preserve">Received with label</source> <context-group purpose="location"><context context-type="linenumber">396</context></context-group> </trans-unit> - <trans-unit id="_msg197"> + <trans-unit id="_msg198"> <source xml:space="preserve">Received with address</source> <context-group purpose="location"><context context-type="linenumber">401</context></context-group> </trans-unit> - <trans-unit id="_msg198"> + <trans-unit id="_msg199"> <source xml:space="preserve">Date</source> <context-group purpose="location"><context context-type="linenumber">406</context></context-group> </trans-unit> - <trans-unit id="_msg199"> + <trans-unit id="_msg200"> <source xml:space="preserve">Confirmations</source> <context-group purpose="location"><context context-type="linenumber">411</context></context-group> </trans-unit> - <trans-unit id="_msg200"> + <trans-unit id="_msg201"> <source xml:space="preserve">Confirmed</source> <context-group purpose="location"><context context-type="linenumber">414</context></context-group> </trans-unit> @@ -885,235 +891,231 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../coincontroldialog.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> - <trans-unit id="_msg201"> + <trans-unit id="_msg202"> <source xml:space="preserve">Copy amount</source> - <context-group purpose="location"><context context-type="linenumber">69</context></context-group> + <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg202"> + <trans-unit id="_msg203"> <source xml:space="preserve">&Copy address</source> - <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + <context-group purpose="location"><context context-type="linenumber">54</context></context-group> </trans-unit> - <trans-unit id="_msg203"> + <trans-unit id="_msg204"> <source xml:space="preserve">Copy &label</source> - <context-group purpose="location"><context context-type="linenumber">59</context></context-group> + <context-group purpose="location"><context context-type="linenumber">55</context></context-group> </trans-unit> - <trans-unit id="_msg204"> + <trans-unit id="_msg205"> <source xml:space="preserve">Copy &amount</source> - <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + <context-group purpose="location"><context context-type="linenumber">56</context></context-group> </trans-unit> - <trans-unit id="_msg205"> + <trans-unit id="_msg206"> <source xml:space="preserve">Copy transaction &ID and output index</source> - <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + <context-group purpose="location"><context context-type="linenumber">57</context></context-group> </trans-unit> - <trans-unit id="_msg206"> + <trans-unit id="_msg207"> <source xml:space="preserve">L&ock unspent</source> - <context-group purpose="location"><context context-type="linenumber">63</context></context-group> + <context-group purpose="location"><context context-type="linenumber">59</context></context-group> </trans-unit> - <trans-unit id="_msg207"> + <trans-unit id="_msg208"> <source xml:space="preserve">&Unlock unspent</source> - <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> - <trans-unit id="_msg208"> + <trans-unit id="_msg209"> <source xml:space="preserve">Copy quantity</source> - <context-group purpose="location"><context context-type="linenumber">68</context></context-group> + <context-group purpose="location"><context context-type="linenumber">64</context></context-group> </trans-unit> - <trans-unit id="_msg209"> + <trans-unit id="_msg210"> <source xml:space="preserve">Copy fee</source> - <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg210"> + <trans-unit id="_msg211"> <source xml:space="preserve">Copy after fee</source> - <context-group purpose="location"><context context-type="linenumber">71</context></context-group> + <context-group purpose="location"><context context-type="linenumber">67</context></context-group> </trans-unit> - <trans-unit id="_msg211"> + <trans-unit id="_msg212"> <source xml:space="preserve">Copy bytes</source> - <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + <context-group purpose="location"><context context-type="linenumber">68</context></context-group> </trans-unit> - <trans-unit id="_msg212"> + <trans-unit id="_msg213"> <source xml:space="preserve">Copy change</source> - <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> - <trans-unit id="_msg213"> + <trans-unit id="_msg214"> <source xml:space="preserve">(%1 locked)</source> - <context-group purpose="location"><context context-type="linenumber">371</context></context-group> + <context-group purpose="location"><context context-type="linenumber">363</context></context-group> </trans-unit> - <trans-unit id="_msg214"> + <trans-unit id="_msg215"> <source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source> - <context-group purpose="location"><context context-type="linenumber">536</context></context-group> + <context-group purpose="location"><context context-type="linenumber">528</context></context-group> </trans-unit> - <trans-unit id="_msg215"> + <trans-unit id="_msg216"> <source xml:space="preserve">(no label)</source> - <context-group purpose="location"><context context-type="linenumber">581</context></context-group> - <context-group purpose="location"><context context-type="linenumber">635</context></context-group> + <context-group purpose="location"><context context-type="linenumber">573</context></context-group> + <context-group purpose="location"><context context-type="linenumber">627</context></context-group> </trans-unit> - <trans-unit id="_msg216"> + <trans-unit id="_msg217"> <source xml:space="preserve">change from %1 (%2)</source> - <context-group purpose="location"><context context-type="linenumber">628</context></context-group> + <context-group purpose="location"><context context-type="linenumber">620</context></context-group> </trans-unit> - <trans-unit id="_msg217"> + <trans-unit id="_msg218"> <source xml:space="preserve">(change)</source> - <context-group purpose="location"><context context-type="linenumber">629</context></context-group> + <context-group purpose="location"><context context-type="linenumber">621</context></context-group> </trans-unit> </group> </body></file> <file original="../walletcontroller.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletActivity"> - <trans-unit id="_msg218"> + <trans-unit id="_msg219"> <source xml:space="preserve">Create Wallet</source> - <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</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="_msg219"> + <trans-unit id="_msg220"> <source xml:space="preserve">Creating Wallet <b>%1</b>…</source> - <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + <context-group purpose="location"><context context-type="linenumber">251</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="_msg220"> - <source xml:space="preserve">Create wallet failed</source> - <context-group purpose="location"><context context-type="linenumber">281</context></context-group> - </trans-unit> <trans-unit id="_msg221"> - <source xml:space="preserve">Create wallet warning</source> + <source xml:space="preserve">Create wallet failed</source> <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> <trans-unit id="_msg222"> - <source xml:space="preserve">Can't list signers</source> - <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <source xml:space="preserve">Create wallet warning</source> + <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> <trans-unit id="_msg223"> + <source xml:space="preserve">Can't list signers</source> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> + </trans-unit> + <trans-unit id="_msg224"> <source xml:space="preserve">Too many external signers found</source> - <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity"> - <trans-unit id="_msg224"> + <trans-unit id="_msg225"> <source xml:space="preserve">Load Wallets</source> - <context-group purpose="location"><context context-type="linenumber">376</context></context-group> + <context-group purpose="location"><context context-type="linenumber">378</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="_msg225"> + <trans-unit id="_msg226"> <source xml:space="preserve">Loading wallets…</source> - <context-group purpose="location"><context context-type="linenumber">379</context></context-group> + <context-group purpose="location"><context context-type="linenumber">381</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="MigrateWalletActivity"> - <trans-unit id="_msg226"> + <trans-unit id="_msg227"> <source xml:space="preserve">Migrate wallet</source> - <context-group purpose="location"><context context-type="linenumber">442</context></context-group> + <context-group purpose="location"><context context-type="linenumber">444</context></context-group> </trans-unit> - <trans-unit id="_msg227"> + <trans-unit id="_msg228"> <source xml:space="preserve">Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <context-group purpose="location"><context context-type="linenumber">443</context></context-group> + <context-group purpose="location"><context context-type="linenumber">445</context></context-group> </trans-unit> - <trans-unit id="_msg228"> + <trans-unit id="_msg229"> <source xml:space="preserve">Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> - <context-group purpose="location"><context context-type="linenumber">444</context></context-group> + <context-group purpose="location"><context context-type="linenumber">446</context></context-group> </trans-unit> - <trans-unit id="_msg229"> + <trans-unit id="_msg230"> <source xml:space="preserve">Migrate Wallet</source> - <context-group purpose="location"><context context-type="linenumber">467</context></context-group> + <context-group purpose="location"><context context-type="linenumber">463</context></context-group> </trans-unit> - <trans-unit id="_msg230"> + <trans-unit id="_msg231"> <source xml:space="preserve">Migrating Wallet <b>%1</b>…</source> - <context-group purpose="location"><context context-type="linenumber">467</context></context-group> + <context-group purpose="location"><context context-type="linenumber">463</context></context-group> </trans-unit> - <trans-unit id="_msg231"> + <trans-unit id="_msg232"> <source xml:space="preserve">The wallet '%1' was migrated successfully.</source> - <context-group purpose="location"><context context-type="linenumber">473</context></context-group> + <context-group purpose="location"><context context-type="linenumber">469</context></context-group> </trans-unit> - <trans-unit id="_msg232"> + <trans-unit id="_msg233"> <source xml:space="preserve">Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <context-group purpose="location"><context context-type="linenumber">475</context></context-group> + <context-group purpose="location"><context context-type="linenumber">471</context></context-group> </trans-unit> - <trans-unit id="_msg233"> + <trans-unit id="_msg234"> <source xml:space="preserve">Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <context-group purpose="location"><context context-type="linenumber">478</context></context-group> + <context-group purpose="location"><context context-type="linenumber">474</context></context-group> </trans-unit> - <trans-unit id="_msg234"> + <trans-unit id="_msg235"> <source xml:space="preserve">Migration failed</source> - <context-group purpose="location"><context context-type="linenumber">492</context></context-group> + <context-group purpose="location"><context context-type="linenumber">488</context></context-group> </trans-unit> - <trans-unit id="_msg235"> + <trans-unit id="_msg236"> <source xml:space="preserve">Migration Successful</source> - <context-group purpose="location"><context context-type="linenumber">494</context></context-group> + <context-group purpose="location"><context context-type="linenumber">490</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="OpenWalletActivity"> - <trans-unit id="_msg236"> - <source xml:space="preserve">Open wallet failed</source> - <context-group purpose="location"><context context-type="linenumber">333</context></context-group> - </trans-unit> <trans-unit id="_msg237"> - <source xml:space="preserve">Open wallet warning</source> + <source xml:space="preserve">Open wallet failed</source> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> <trans-unit id="_msg238"> - <source xml:space="preserve">default wallet</source> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <source xml:space="preserve">Open wallet warning</source> + <context-group purpose="location"><context context-type="linenumber">337</context></context-group> </trans-unit> <trans-unit id="_msg239"> <source xml:space="preserve">Open Wallet</source> - <context-group purpose="location"><context context-type="linenumber">349</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</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="_msg240"> <source xml:space="preserve">Opening Wallet <b>%1</b>…</source> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + <context-group purpose="location"><context context-type="linenumber">354</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="_msg241"> <source xml:space="preserve">Restore Wallet</source> - <context-group purpose="location"><context context-type="linenumber">402</context></context-group> + <context-group purpose="location"><context context-type="linenumber">404</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="_msg242"> <source xml:space="preserve">Restoring Wallet <b>%1</b>…</source> - <context-group purpose="location"><context context-type="linenumber">405</context></context-group> + <context-group purpose="location"><context context-type="linenumber">407</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="_msg243"> <source xml:space="preserve">Restore wallet failed</source> - <context-group purpose="location"><context context-type="linenumber">424</context></context-group> + <context-group purpose="location"><context context-type="linenumber">426</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="_msg244"> <source xml:space="preserve">Restore wallet warning</source> - <context-group purpose="location"><context context-type="linenumber">427</context></context-group> + <context-group purpose="location"><context context-type="linenumber">429</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="_msg245"> <source xml:space="preserve">Restore wallet message</source> - <context-group purpose="location"><context context-type="linenumber">430</context></context-group> + <context-group purpose="location"><context context-type="linenumber">432</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="_msg246"> <source xml:space="preserve">Close wallet</source> - <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> <trans-unit id="_msg247"> <source xml:space="preserve">Are you sure you wish to close the wallet <i>%1</i>?</source> - <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> <trans-unit id="_msg248"> <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> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> <trans-unit id="_msg249"> <source xml:space="preserve">Close all wallets</source> - <context-group purpose="location"><context context-type="linenumber">99</context></context-group> + <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> <trans-unit id="_msg250"> <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> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> </group> </body></file> @@ -1181,11 +1183,11 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> <trans-unit id="_msg265"> <source xml:space="preserve">Create</source> - <context-group purpose="location"><context context-type="linenumber">22</context></context-group> + <context-group purpose="location"><context context-type="linenumber">20</context></context-group> </trans-unit> <trans-unit id="_msg266"> <source xml:space="preserve">Compiled without external signing support (required for external signing)</source> - <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> <note annotates="source" from="developer">"External signing" means using devices such as hardware wallets.</note> </trans-unit> </group> @@ -1254,32 +1256,32 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="FreespaceChecker"> <trans-unit id="_msg280"> <source xml:space="preserve">A new data directory will be created.</source> - <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> <trans-unit id="_msg281"> <source xml:space="preserve">name</source> - <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> <trans-unit id="_msg282"> <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">99</context></context-group> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> <trans-unit id="_msg283"> <source xml:space="preserve">Path already exists, and is not a directory.</source> - <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> <trans-unit id="_msg284"> <source xml:space="preserve">Cannot create data directory here.</source> - <context-group purpose="location"><context context-type="linenumber">109</context></context-group> + <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="_msg285"> <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">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> <trans-unit id="_msg286[0]"> <source xml:space="preserve">%n GB of space available</source> </trans-unit> @@ -1288,7 +1290,7 @@ The migration process will create a backup of the wallet before migrating. This </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> <trans-unit id="_msg287[0]"> <source xml:space="preserve">(of %n GB needed)</source> </trans-unit> @@ -1297,7 +1299,7 @@ The migration process will create a backup of the wallet before migrating. This </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> <trans-unit id="_msg288[0]"> <source xml:space="preserve">(%n GB needed for full chain)</source> </trans-unit> @@ -1307,18 +1309,18 @@ The migration process will create a backup of the wallet before migrating. This </group> <trans-unit id="_msg289"> <source xml:space="preserve">Choose data directory</source> - <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> <trans-unit id="_msg290"> <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">380</context></context-group> + <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> <trans-unit id="_msg291"> <source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source> - <context-group purpose="location"><context context-type="linenumber">383</context></context-group> + <context-group purpose="location"><context context-type="linenumber">381</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">392</context></context-group> + <context-group purpose="location"><context context-type="linenumber">390</context></context-group> <note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note> <trans-unit id="_msg292[0]"> <source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source> @@ -1329,19 +1331,19 @@ The migration process will create a backup of the wallet before migrating. This </group> <trans-unit id="_msg293"> <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">394</context></context-group> + <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> <trans-unit id="_msg294"> <source xml:space="preserve">The wallet will also be stored in this directory.</source> - <context-group purpose="location"><context context-type="linenumber">396</context></context-group> + <context-group purpose="location"><context context-type="linenumber">394</context></context-group> </trans-unit> <trans-unit id="_msg295"> <source xml:space="preserve">Error: Specified data directory "%1" cannot be created.</source> - <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> <trans-unit id="_msg296"> <source xml:space="preserve">Error</source> - <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> </trans-unit> </group> </body></file> @@ -1349,25 +1351,25 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="HelpMessageDialog"> <trans-unit id="_msg297"> <source xml:space="preserve">version</source> - <context-group purpose="location"><context context-type="linenumber">38</context></context-group> + <context-group purpose="location"><context context-type="linenumber">36</context></context-group> </trans-unit> <trans-unit id="_msg298"> <source xml:space="preserve">About %1</source> - <context-group purpose="location"><context context-type="linenumber">42</context></context-group> + <context-group purpose="location"><context context-type="linenumber">40</context></context-group> </trans-unit> <trans-unit id="_msg299"> <source xml:space="preserve">Command-line options</source> - <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="ShutdownWindow"> <trans-unit id="_msg300"> <source xml:space="preserve">%1 is shutting down…</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="_msg301"> <source xml:space="preserve">Do not shut down the computer until this window disappears.</source> - <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> </group> </body></file> @@ -1441,7 +1443,7 @@ The migration process will create a backup of the wallet before migrating. This <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">152</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">160</context></context-group> </trans-unit> <trans-unit id="_msg318"> <source xml:space="preserve">calculating…</source> @@ -1478,21 +1480,21 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> <trans-unit id="_msg325"> <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">31</context></context-group> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> <trans-unit id="_msg326"> <source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source> - <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + <context-group purpose="location"><context context-type="linenumber">166</context></context-group> </trans-unit> <trans-unit id="_msg327"> <source xml:space="preserve">Unknown. Pre-syncing Headers (%1, %2%)…</source> - <context-group purpose="location"><context context-type="linenumber">163</context></context-group> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="QObject"> <trans-unit id="_msg328"> <source xml:space="preserve">unknown</source> - <context-group purpose="location"><context context-type="linenumber">123</context></context-group> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> </group> </body></file> @@ -1820,85 +1822,85 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> <trans-unit id="_msg403"> <source xml:space="preserve">Compiled without external signing support (required for external signing)</source> - <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> <note annotates="source" from="developer">"External signing" means using devices such as hardware wallets.</note> </trans-unit> <trans-unit id="_msg404"> <source xml:space="preserve">default</source> - <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> </trans-unit> <trans-unit id="_msg405"> <source xml:space="preserve">none</source> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <context-group purpose="location"><context context-type="linenumber">239</context></context-group> </trans-unit> <trans-unit id="_msg406"> <source xml:space="preserve">Confirm options reset</source> - <context-group purpose="location"><context context-type="linenumber">347</context></context-group> + <context-group purpose="location"><context context-type="linenumber">348</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="_msg407"> <source xml:space="preserve">Client restart required to activate changes.</source> - <context-group purpose="location"><context context-type="linenumber">338</context></context-group> - <context-group purpose="location"><context context-type="linenumber">419</context></context-group> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + <context-group purpose="location"><context context-type="linenumber">420</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="_msg408"> <source xml:space="preserve">Current settings will be backed up at "%1".</source> - <context-group purpose="location"><context context-type="linenumber">342</context></context-group> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> <note annotates="source" from="developer">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.</note> </trans-unit> <trans-unit id="_msg409"> <source xml:space="preserve">Client will be shut down. Do you want to proceed?</source> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">346</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="_msg410"> <source xml:space="preserve">Configuration options</source> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">366</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="_msg411"> <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">368</context></context-group> + <context-group purpose="location"><context context-type="linenumber">369</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="_msg412"> <source xml:space="preserve">Continue</source> - <context-group purpose="location"><context context-type="linenumber">371</context></context-group> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> </trans-unit> <trans-unit id="_msg413"> <source xml:space="preserve">Cancel</source> - <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> <trans-unit id="_msg414"> <source xml:space="preserve">Error</source> - <context-group purpose="location"><context context-type="linenumber">381</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> <trans-unit id="_msg415"> <source xml:space="preserve">The configuration file could not be opened.</source> - <context-group purpose="location"><context context-type="linenumber">381</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> <trans-unit id="_msg416"> <source xml:space="preserve">This change would require a client restart.</source> - <context-group purpose="location"><context context-type="linenumber">423</context></context-group> + <context-group purpose="location"><context context-type="linenumber">424</context></context-group> </trans-unit> <trans-unit id="_msg417"> <source xml:space="preserve">The supplied proxy address is invalid.</source> - <context-group purpose="location"><context context-type="linenumber">451</context></context-group> + <context-group purpose="location"><context context-type="linenumber">452</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="QObject"> <trans-unit id="_msg418"> <source xml:space="preserve">Embedded "%1"</source> - <context-group purpose="location"><context context-type="linenumber">62</context></context-group> + <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> <trans-unit id="_msg419"> <source xml:space="preserve">Default system font "%1"</source> - <context-group purpose="location"><context context-type="linenumber">63</context></context-group> + <context-group purpose="location"><context context-type="linenumber">62</context></context-group> </trans-unit> <trans-unit id="_msg420"> <source xml:space="preserve">Custom…</source> - <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + <context-group purpose="location"><context context-type="linenumber">63</context></context-group> </trans-unit> </group> </body></file> @@ -1906,7 +1908,7 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="OptionsModel"> <trans-unit id="_msg421"> <source xml:space="preserve">Could not read setting "%1", %2.</source> - <context-group purpose="location"><context context-type="linenumber">230</context></context-group> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> </group> </body></file> @@ -2027,112 +2029,112 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> <trans-unit id="_msg447"> <source xml:space="preserve">Failed to load transaction: %1</source> - <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + <context-group purpose="location"><context context-type="linenumber">64</context></context-group> </trans-unit> <trans-unit id="_msg448"> <source xml:space="preserve">Failed to sign transaction: %1</source> - <context-group purpose="location"><context context-type="linenumber">85</context></context-group> + <context-group purpose="location"><context context-type="linenumber">89</context></context-group> </trans-unit> <trans-unit id="_msg449"> <source xml:space="preserve">Cannot sign inputs while wallet is locked.</source> - <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> <trans-unit id="_msg450"> <source xml:space="preserve">Could not sign any more inputs.</source> - <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + <context-group purpose="location"><context context-type="linenumber">99</context></context-group> </trans-unit> <trans-unit id="_msg451"> <source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source> - <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> <trans-unit id="_msg452"> <source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source> - <context-group purpose="location"><context context-type="linenumber">100</context></context-group> + <context-group purpose="location"><context context-type="linenumber">104</context></context-group> </trans-unit> <trans-unit id="_msg453"> <source xml:space="preserve">Unknown error processing transaction.</source> - <context-group purpose="location"><context context-type="linenumber">112</context></context-group> + <context-group purpose="location"><context context-type="linenumber">116</context></context-group> </trans-unit> <trans-unit id="_msg454"> <source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source> - <context-group purpose="location"><context context-type="linenumber">122</context></context-group> + <context-group purpose="location"><context context-type="linenumber">126</context></context-group> </trans-unit> <trans-unit id="_msg455"> <source xml:space="preserve">Transaction broadcast failed: %1</source> - <context-group purpose="location"><context context-type="linenumber">125</context></context-group> + <context-group purpose="location"><context context-type="linenumber">129</context></context-group> </trans-unit> <trans-unit id="_msg456"> <source xml:space="preserve">PSBT copied to clipboard.</source> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> <trans-unit id="_msg457"> <source xml:space="preserve">Save Transaction Data</source> - <context-group purpose="location"><context context-type="linenumber">157</context></context-group> + <context-group purpose="location"><context context-type="linenumber">161</context></context-group> </trans-unit> <trans-unit id="_msg458"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> - <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + <context-group purpose="location"><context context-type="linenumber">163</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="_msg459"> <source xml:space="preserve">PSBT saved to disk.</source> - <context-group purpose="location"><context context-type="linenumber">166</context></context-group> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> <trans-unit id="_msg460"> <source xml:space="preserve">Sends %1 to %2</source> - <context-group purpose="location"><context context-type="linenumber">183</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> <trans-unit id="_msg461"> <source xml:space="preserve">own address</source> - <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> </trans-unit> <trans-unit id="_msg462"> <source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source> - <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> </trans-unit> <trans-unit id="_msg463"> <source xml:space="preserve">Pays transaction fee: </source> - <context-group purpose="location"><context context-type="linenumber">197</context></context-group> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> </trans-unit> <trans-unit id="_msg464"> <source xml:space="preserve">Total Amount</source> - <context-group purpose="location"><context context-type="linenumber">209</context></context-group> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> <trans-unit id="_msg465"> <source xml:space="preserve">or</source> - <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> <trans-unit id="_msg466"> <source xml:space="preserve">Transaction has %1 unsigned inputs.</source> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> <trans-unit id="_msg467"> <source xml:space="preserve">Transaction is missing some information about inputs.</source> - <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> </trans-unit> <trans-unit id="_msg468"> <source xml:space="preserve">Transaction still needs signature(s).</source> - <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + <context-group purpose="location"><context context-type="linenumber">272</context></context-group> </trans-unit> <trans-unit id="_msg469"> <source xml:space="preserve">(But no wallet is loaded.)</source> - <context-group purpose="location"><context context-type="linenumber">271</context></context-group> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> <trans-unit id="_msg470"> <source xml:space="preserve">(But this wallet cannot sign transactions.)</source> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> </trans-unit> <trans-unit id="_msg471"> <source xml:space="preserve">(But this wallet does not have the right keys.)</source> - <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> </trans-unit> <trans-unit id="_msg472"> <source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <context-group purpose="location"><context context-type="linenumber">289</context></context-group> </trans-unit> <trans-unit id="_msg473"> <source xml:space="preserve">Transaction status is unknown.</source> - <context-group purpose="location"><context context-type="linenumber">289</context></context-group> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> </group> </body></file> @@ -2140,37 +2142,37 @@ The migration process will create a backup of the wallet before migrating. This <group restype="x-trolltech-linguist-context" resname="PaymentServer"> <trans-unit id="_msg474"> <source xml:space="preserve">Payment request error</source> - <context-group purpose="location"><context context-type="linenumber">149</context></context-group> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> <trans-unit id="_msg475"> <source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source> - <context-group purpose="location"><context context-type="linenumber">150</context></context-group> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> <trans-unit id="_msg476"> <source xml:space="preserve">URI handling</source> - <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> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + <context-group purpose="location"><context context-type="linenumber">223</context></context-group> </trans-unit> <trans-unit id="_msg477"> <source xml:space="preserve">'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> - <context-group purpose="location"><context context-type="linenumber">198</context></context-group> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> </trans-unit> <trans-unit id="_msg478"> <source xml:space="preserve">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> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <context-group purpose="location"><context context-type="linenumber">211</context></context-group> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> </trans-unit> <trans-unit id="_msg479"> <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">228</context></context-group> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> <trans-unit id="_msg480"> <source xml:space="preserve">Payment request file handling</source> - <context-group purpose="location"><context context-type="linenumber">237</context></context-group> + <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> </group> </body></file> @@ -2254,116 +2256,116 @@ If you are receiving this error you should request the merchant provide a BIP21 <group restype="x-trolltech-linguist-context" resname="QObject"> <trans-unit id="_msg494"> <source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source> - <context-group purpose="location"><context context-type="linenumber">133</context></context-group> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> <trans-unit id="_msg495"> <source xml:space="preserve">Ctrl+W</source> - <context-group purpose="location"><context context-type="linenumber">421</context></context-group> + <context-group purpose="location"><context context-type="linenumber">433</context></context-group> </trans-unit> <trans-unit id="_msg496"> <source xml:space="preserve">Unroutable</source> - <context-group purpose="location"><context context-type="linenumber">678</context></context-group> + <context-group purpose="location"><context context-type="linenumber">690</context></context-group> </trans-unit> <trans-unit id="_msg497"> <source xml:space="preserve">IPv4</source> - <context-group purpose="location"><context context-type="linenumber">680</context></context-group> + <context-group purpose="location"><context context-type="linenumber">692</context></context-group> <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group> <note annotates="source" from="developer">Name of IPv4 network in peer info</note> </trans-unit> <trans-unit id="_msg498"> <source xml:space="preserve">IPv6</source> - <context-group purpose="location"><context context-type="linenumber">682</context></context-group> + <context-group purpose="location"><context context-type="linenumber">694</context></context-group> <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group> <note annotates="source" from="developer">Name of IPv6 network in peer info</note> </trans-unit> <trans-unit id="_msg499"> <source xml:space="preserve">Onion</source> - <context-group purpose="location"><context context-type="linenumber">684</context></context-group> + <context-group purpose="location"><context context-type="linenumber">696</context></context-group> <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group> <note annotates="source" from="developer">Name of Tor network in peer info</note> </trans-unit> <trans-unit id="_msg500"> <source xml:space="preserve">I2P</source> - <context-group purpose="location"><context context-type="linenumber">686</context></context-group> + <context-group purpose="location"><context context-type="linenumber">698</context></context-group> <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group> <note annotates="source" from="developer">Name of I2P network in peer info</note> </trans-unit> <trans-unit id="_msg501"> <source xml:space="preserve">CJDNS</source> - <context-group purpose="location"><context context-type="linenumber">688</context></context-group> + <context-group purpose="location"><context context-type="linenumber">700</context></context-group> <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group> <note annotates="source" from="developer">Name of CJDNS network in peer info</note> </trans-unit> <trans-unit id="_msg502"> <source xml:space="preserve">Inbound</source> - <context-group purpose="location"><context context-type="linenumber">702</context></context-group> + <context-group purpose="location"><context context-type="linenumber">714</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="_msg503"> <source xml:space="preserve">Outbound</source> - <context-group purpose="location"><context context-type="linenumber">705</context></context-group> + <context-group purpose="location"><context context-type="linenumber">717</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="_msg504"> <source xml:space="preserve">Full Relay</source> - <context-group purpose="location"><context context-type="linenumber">710</context></context-group> + <context-group purpose="location"><context context-type="linenumber">722</context></context-group> <note annotates="source" from="developer">Peer connection type that relays all network information.</note> </trans-unit> <trans-unit id="_msg505"> <source xml:space="preserve">Block Relay</source> - <context-group purpose="location"><context context-type="linenumber">713</context></context-group> + <context-group purpose="location"><context context-type="linenumber">725</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="_msg506"> <source xml:space="preserve">Manual</source> - <context-group purpose="location"><context context-type="linenumber">715</context></context-group> + <context-group purpose="location"><context context-type="linenumber">727</context></context-group> <note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note> </trans-unit> <trans-unit id="_msg507"> <source xml:space="preserve">Feeler</source> - <context-group purpose="location"><context context-type="linenumber">717</context></context-group> + <context-group purpose="location"><context context-type="linenumber">729</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="_msg508"> <source xml:space="preserve">Address Fetch</source> - <context-group purpose="location"><context context-type="linenumber">719</context></context-group> + <context-group purpose="location"><context context-type="linenumber">731</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="_msg509"> <source xml:space="preserve">%1 d</source> - <context-group purpose="location"><context context-type="linenumber">731</context></context-group> <context-group purpose="location"><context context-type="linenumber">743</context></context-group> + <context-group purpose="location"><context context-type="linenumber">755</context></context-group> </trans-unit> <trans-unit id="_msg510"> <source xml:space="preserve">%1 h</source> - <context-group purpose="location"><context context-type="linenumber">732</context></context-group> <context-group purpose="location"><context context-type="linenumber">744</context></context-group> + <context-group purpose="location"><context context-type="linenumber">756</context></context-group> </trans-unit> <trans-unit id="_msg511"> <source xml:space="preserve">%1 m</source> - <context-group purpose="location"><context context-type="linenumber">733</context></context-group> <context-group purpose="location"><context context-type="linenumber">745</context></context-group> + <context-group purpose="location"><context context-type="linenumber">757</context></context-group> </trans-unit> <trans-unit id="_msg512"> <source xml:space="preserve">%1 s</source> - <context-group purpose="location"><context context-type="linenumber">735</context></context-group> - <context-group purpose="location"><context context-type="linenumber">746</context></context-group> - <context-group purpose="location"><context context-type="linenumber">772</context></context-group> + <context-group purpose="location"><context context-type="linenumber">747</context></context-group> + <context-group purpose="location"><context context-type="linenumber">758</context></context-group> + <context-group purpose="location"><context context-type="linenumber">784</context></context-group> </trans-unit> <trans-unit id="_msg513"> <source xml:space="preserve">None</source> - <context-group purpose="location"><context context-type="linenumber">760</context></context-group> + <context-group purpose="location"><context context-type="linenumber">772</context></context-group> </trans-unit> <trans-unit id="_msg514"> <source xml:space="preserve">N/A</source> - <context-group purpose="location"><context context-type="linenumber">766</context></context-group> + <context-group purpose="location"><context context-type="linenumber">778</context></context-group> </trans-unit> <trans-unit id="_msg515"> <source xml:space="preserve">%1 ms</source> - <context-group purpose="location"><context context-type="linenumber">767</context></context-group> + <context-group purpose="location"><context context-type="linenumber">779</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">785</context></context-group> + <context-group purpose="location"><context context-type="linenumber">797</context></context-group> <trans-unit id="_msg516[0]"> <source xml:space="preserve">%n second(s)</source> </trans-unit> @@ -2372,7 +2374,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">789</context></context-group> + <context-group purpose="location"><context context-type="linenumber">801</context></context-group> <trans-unit id="_msg517[0]"> <source xml:space="preserve">%n minute(s)</source> </trans-unit> @@ -2381,7 +2383,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">793</context></context-group> + <context-group purpose="location"><context context-type="linenumber">805</context></context-group> <trans-unit id="_msg518[0]"> <source xml:space="preserve">%n hour(s)</source> </trans-unit> @@ -2390,7 +2392,7 @@ If you are receiving this error you should request the merchant provide a BIP21 </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">797</context></context-group> + <context-group purpose="location"><context context-type="linenumber">809</context></context-group> <trans-unit id="_msg519[0]"> <source xml:space="preserve">%n day(s)</source> </trans-unit> @@ -2399,8 +2401,8 @@ If you are receiving this error you should request the merchant provide a BIP21 </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">801</context></context-group> - <context-group purpose="location"><context context-type="linenumber">807</context></context-group> + <context-group purpose="location"><context context-type="linenumber">813</context></context-group> + <context-group purpose="location"><context context-type="linenumber">819</context></context-group> <trans-unit id="_msg520[0]"> <source xml:space="preserve">%n week(s)</source> </trans-unit> @@ -2410,10 +2412,10 @@ If you are receiving this error you should request the merchant provide a BIP21 </group> <trans-unit id="_msg521"> <source xml:space="preserve">%1 and %2</source> - <context-group purpose="location"><context context-type="linenumber">807</context></context-group> + <context-group purpose="location"><context context-type="linenumber">819</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">807</context></context-group> + <context-group purpose="location"><context context-type="linenumber">819</context></context-group> <trans-unit id="_msg522[0]"> <source xml:space="preserve">%n year(s)</source> </trans-unit> @@ -2423,60 +2425,65 @@ If you are receiving this error you should request the merchant provide a BIP21 </group> <trans-unit id="_msg523"> <source xml:space="preserve">%1 B</source> - <context-group purpose="location"><context context-type="linenumber">815</context></context-group> + <context-group purpose="location"><context context-type="linenumber">827</context></context-group> </trans-unit> <trans-unit id="_msg524"> <source xml:space="preserve">%1 kB</source> - <context-group purpose="location"><context context-type="linenumber">817</context></context-group> - <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1006</context></context-group> + <context-group purpose="location"><context context-type="linenumber">829</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1021</context></context-group> </trans-unit> <trans-unit id="_msg525"> <source xml:space="preserve">%1 MB</source> - <context-group purpose="location"><context context-type="linenumber">819</context></context-group> - <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1008</context></context-group> + <context-group purpose="location"><context context-type="linenumber">831</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1022</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1023</context></context-group> </trans-unit> <trans-unit id="_msg526"> <source xml:space="preserve">%1 GB</source> - <context-group purpose="location"><context context-type="linenumber">821</context></context-group> + <context-group purpose="location"><context context-type="linenumber">833</context></context-group> + </trans-unit> + <trans-unit id="_msg527"> + <source xml:space="preserve">default wallet</source> + <context-group purpose="location"><context context-type="linenumber">1013</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="_msg527"> + <trans-unit id="_msg528"> <source xml:space="preserve">&Save Image…</source> - <context-group purpose="location"><context context-type="linenumber">30</context></context-group> + <context-group purpose="location"><context context-type="linenumber">28</context></context-group> </trans-unit> - <trans-unit id="_msg528"> + <trans-unit id="_msg529"> <source xml:space="preserve">&Copy Image</source> - <context-group purpose="location"><context context-type="linenumber">31</context></context-group> + <context-group purpose="location"><context context-type="linenumber">29</context></context-group> </trans-unit> - <trans-unit id="_msg529"> + <trans-unit id="_msg530"> <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> + <context-group purpose="location"><context context-type="linenumber">40</context></context-group> </trans-unit> - <trans-unit id="_msg530"> + <trans-unit id="_msg531"> <source xml:space="preserve">Error encoding URI into QR Code.</source> - <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg531"> + <trans-unit id="_msg532"> <source xml:space="preserve">QR code support not available.</source> - <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg532"> + <trans-unit id="_msg533"> <source xml:space="preserve">Save QR Code</source> - <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> </trans-unit> - <trans-unit id="_msg533"> + <trans-unit id="_msg534"> <source xml:space="preserve">PNG Image</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> <note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note> </trans-unit> </group> </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="_msg534"> + <trans-unit id="_msg535"> <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> @@ -2485,500 +2492,520 @@ If you are receiving this error you should request the merchant provide a BIP21 <context-group purpose="location"><context context-type="linenumber">182</context></context-group> <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">277</context></context-group> - <context-group purpose="location"><context context-type="linenumber">300</context></context-group> - <context-group purpose="location"><context context-type="linenumber">336</context></context-group> - <context-group purpose="location"><context context-type="linenumber">359</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1051</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1077</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1103</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1129</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1155</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1178</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1224</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1253</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1279</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1302</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1325</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1348</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1371</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1397</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1423</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1446</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1469</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1492</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1515</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1538</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1564</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1587</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1610</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1636</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1662</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1688</context></context-group> - <context-group purpose="location"><context context-type="linenumber">1714</context></context-group> - <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> + <context-group purpose="location"><context context-type="linenumber">394</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1161</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1187</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1213</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1239</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1265</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1288</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1311</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1334</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1363</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1389</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1412</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1435</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1458</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1481</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1507</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1533</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1556</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1579</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1602</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1625</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1648</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1674</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1697</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1720</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1746</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1772</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1798</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1824</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg535"> + <trans-unit id="_msg536"> <source xml:space="preserve">Client version</source> <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg536"> + <trans-unit id="_msg537"> <source xml:space="preserve">&Information</source> <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg537"> + <trans-unit id="_msg538"> <source xml:space="preserve">General</source> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg538"> + <trans-unit id="_msg539"> <source xml:space="preserve">Datadir</source> <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> - <trans-unit id="_msg539"> + <trans-unit id="_msg540"> <source xml:space="preserve">To specify a non-default location of the data directory use the '%1' option.</source> <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg540"> + <trans-unit id="_msg541"> <source xml:space="preserve">Blocksdir</source> <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg541"> + <trans-unit id="_msg542"> <source xml:space="preserve">To specify a non-default location of the blocks directory use the '%1' option.</source> <context-group purpose="location"><context context-type="linenumber">153</context></context-group> </trans-unit> - <trans-unit id="_msg542"> + <trans-unit id="_msg543"> <source xml:space="preserve">Startup time</source> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg543"> + <trans-unit id="_msg544"> <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">1145</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1255</context></context-group> </trans-unit> - <trans-unit id="_msg544"> + <trans-unit id="_msg545"> <source xml:space="preserve">Name</source> <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> - <trans-unit id="_msg545"> + <trans-unit id="_msg546"> <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="_msg546"> - <source xml:space="preserve">Block chain</source> - <context-group purpose="location"><context context-type="linenumber">260</context></context-group> - </trans-unit> <trans-unit id="_msg547"> - <source xml:space="preserve">Memory Pool</source> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <source xml:space="preserve">Local Addresses</source> + <context-group purpose="location"><context context-type="linenumber">254</context></context-group> </trans-unit> <trans-unit id="_msg548"> - <source xml:space="preserve">Current number of transactions</source> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <source xml:space="preserve">Network addresses that your Bitcoin node is currently using to communicate with other nodes.</source> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> </trans-unit> <trans-unit id="_msg549"> - <source xml:space="preserve">Memory usage</source> - <context-group purpose="location"><context context-type="linenumber">349</context></context-group> + <source xml:space="preserve">Block chain</source> + <context-group purpose="location"><context context-type="linenumber">295</context></context-group> </trans-unit> <trans-unit id="_msg550"> - <source xml:space="preserve">Wallet: </source> - <context-group purpose="location"><context context-type="linenumber">443</context></context-group> + <source xml:space="preserve">Memory Pool</source> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> </trans-unit> <trans-unit id="_msg551"> - <source xml:space="preserve">(none)</source> - <context-group purpose="location"><context context-type="linenumber">454</context></context-group> + <source xml:space="preserve">Current number of transactions</source> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> </trans-unit> <trans-unit id="_msg552"> - <source xml:space="preserve">&Reset</source> - <context-group purpose="location"><context context-type="linenumber">665</context></context-group> + <source xml:space="preserve">Memory usage</source> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> </trans-unit> <trans-unit id="_msg553"> - <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">1505</context></context-group> + <source xml:space="preserve">Wallet: </source> + <context-group purpose="location"><context context-type="linenumber">478</context></context-group> </trans-unit> <trans-unit id="_msg554"> - <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">1482</context></context-group> + <source xml:space="preserve">(none)</source> + <context-group purpose="location"><context context-type="linenumber">489</context></context-group> </trans-unit> <trans-unit id="_msg555"> - <source xml:space="preserve">&Peers</source> - <context-group purpose="location"><context context-type="linenumber">866</context></context-group> + <source xml:space="preserve">&Reset</source> + <context-group purpose="location"><context context-type="linenumber">700</context></context-group> </trans-unit> <trans-unit id="_msg556"> - <source xml:space="preserve">Banned peers</source> - <context-group purpose="location"><context context-type="linenumber">942</context></context-group> + <source xml:space="preserve">Received</source> + <context-group purpose="location"><context context-type="linenumber">780</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1615</context></context-group> </trans-unit> <trans-unit id="_msg557"> - <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">1173</context></context-group> + <source xml:space="preserve">Sent</source> + <context-group purpose="location"><context context-type="linenumber">860</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1592</context></context-group> </trans-unit> <trans-unit id="_msg558"> - <source xml:space="preserve">The transport layer version: %1</source> - <context-group purpose="location"><context context-type="linenumber">1090</context></context-group> + <source xml:space="preserve">&Peers</source> + <context-group purpose="location"><context context-type="linenumber">901</context></context-group> </trans-unit> <trans-unit id="_msg559"> - <source xml:space="preserve">Transport</source> - <context-group purpose="location"><context context-type="linenumber">1093</context></context-group> + <source xml:space="preserve">Banned peers</source> + <context-group purpose="location"><context context-type="linenumber">977</context></context-group> </trans-unit> <trans-unit id="_msg560"> - <source xml:space="preserve">The BIP324 session ID string in hex, if any.</source> - <context-group purpose="location"><context context-type="linenumber">1116</context></context-group> + <source xml:space="preserve">Select a peer to view detailed information.</source> + <context-group purpose="location"><context context-type="linenumber">1053</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1189</context></context-group> </trans-unit> <trans-unit id="_msg561"> - <source xml:space="preserve">Session ID</source> - <context-group purpose="location"><context context-type="linenumber">1119</context></context-group> + <source xml:space="preserve">Hide Peers Detail</source> + <context-group purpose="location"><context context-type="linenumber">1105</context></context-group> </trans-unit> <trans-unit id="_msg562"> - <source xml:space="preserve">Version</source> - <context-group purpose="location"><context context-type="linenumber">1168</context></context-group> + <source xml:space="preserve">Ctrl+X</source> + <context-group purpose="location"><context context-type="linenumber">1126</context></context-group> </trans-unit> <trans-unit id="_msg563"> - <source xml:space="preserve">Whether we relay transactions to this peer.</source> - <context-group purpose="location"><context context-type="linenumber">1240</context></context-group> + <source xml:space="preserve">The transport layer version: %1</source> + <context-group purpose="location"><context context-type="linenumber">1200</context></context-group> </trans-unit> <trans-unit id="_msg564"> - <source xml:space="preserve">Transaction Relay</source> - <context-group purpose="location"><context context-type="linenumber">1243</context></context-group> + <source xml:space="preserve">Transport</source> + <context-group purpose="location"><context context-type="linenumber">1203</context></context-group> </trans-unit> <trans-unit id="_msg565"> - <source xml:space="preserve">Starting Block</source> - <context-group purpose="location"><context context-type="linenumber">1292</context></context-group> + <source xml:space="preserve">Session ID</source> + <context-group purpose="location"><context context-type="linenumber">1229</context></context-group> </trans-unit> <trans-unit id="_msg566"> - <source xml:space="preserve">Synced Headers</source> - <context-group purpose="location"><context context-type="linenumber">1315</context></context-group> + <source xml:space="preserve">Version</source> + <context-group purpose="location"><context context-type="linenumber">1278</context></context-group> </trans-unit> <trans-unit id="_msg567"> - <source xml:space="preserve">Synced Blocks</source> - <context-group purpose="location"><context context-type="linenumber">1338</context></context-group> + <source xml:space="preserve">Whether we relay transactions to this peer.</source> + <context-group purpose="location"><context context-type="linenumber">1350</context></context-group> </trans-unit> <trans-unit id="_msg568"> - <source xml:space="preserve">Last Transaction</source> - <context-group purpose="location"><context context-type="linenumber">1413</context></context-group> + <source xml:space="preserve">Transaction Relay</source> + <context-group purpose="location"><context context-type="linenumber">1353</context></context-group> </trans-unit> <trans-unit id="_msg569"> - <source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source> - <context-group purpose="location"><context context-type="linenumber">1623</context></context-group> + <source xml:space="preserve">Starting Block</source> + <context-group purpose="location"><context context-type="linenumber">1402</context></context-group> </trans-unit> <trans-unit id="_msg570"> - <source xml:space="preserve">Mapped AS</source> - <context-group purpose="location"><context context-type="linenumber">1626</context></context-group> + <source xml:space="preserve">Synced Headers</source> + <context-group purpose="location"><context context-type="linenumber">1425</context></context-group> </trans-unit> <trans-unit id="_msg571"> + <source xml:space="preserve">Synced Blocks</source> + <context-group purpose="location"><context context-type="linenumber">1448</context></context-group> + </trans-unit> + <trans-unit id="_msg572"> + <source xml:space="preserve">Last Transaction</source> + <context-group purpose="location"><context context-type="linenumber">1523</context></context-group> + </trans-unit> + <trans-unit id="_msg573"> + <source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source> + <context-group purpose="location"><context context-type="linenumber">1733</context></context-group> + </trans-unit> + <trans-unit id="_msg574"> + <source xml:space="preserve">Mapped AS</source> + <context-group purpose="location"><context context-type="linenumber">1736</context></context-group> + </trans-unit> + <trans-unit id="_msg575"> <source xml:space="preserve">Whether we relay addresses to this peer.</source> - <context-group purpose="location"><context context-type="linenumber">1649</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1759</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="_msg572"> + <trans-unit id="_msg576"> <source xml:space="preserve">Address Relay</source> - <context-group purpose="location"><context context-type="linenumber">1652</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1762</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="_msg573"> + <trans-unit id="_msg577"> <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">1675</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1785</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="_msg574"> + <trans-unit id="_msg578"> <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">1701</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1811</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="_msg575"> + <trans-unit id="_msg579"> <source xml:space="preserve">Addresses Processed</source> - <context-group purpose="location"><context context-type="linenumber">1678</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1788</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="_msg576"> + <trans-unit id="_msg580"> <source xml:space="preserve">Addresses Rate-Limited</source> - <context-group purpose="location"><context context-type="linenumber">1704</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1814</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="_msg577"> + <trans-unit id="_msg581"> <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">1191</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1301</context></context-group> </trans-unit> - <trans-unit id="_msg578"> + <trans-unit id="_msg582"> <source xml:space="preserve">Node window</source> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg579"> + <trans-unit id="_msg583"> <source xml:space="preserve">Current block height</source> - <context-group purpose="location"><context context-type="linenumber">267</context></context-group> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> - <trans-unit id="_msg580"> + <trans-unit id="_msg584"> <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> + <context-group purpose="location"><context context-type="linenumber">432</context></context-group> </trans-unit> - <trans-unit id="_msg581"> + <trans-unit id="_msg585"> <source xml:space="preserve">Decrease font size</source> - <context-group purpose="location"><context context-type="linenumber">475</context></context-group> + <context-group purpose="location"><context context-type="linenumber">510</context></context-group> </trans-unit> - <trans-unit id="_msg582"> + <trans-unit id="_msg586"> <source xml:space="preserve">Increase font size</source> - <context-group purpose="location"><context context-type="linenumber">495</context></context-group> + <context-group purpose="location"><context context-type="linenumber">530</context></context-group> </trans-unit> - <trans-unit id="_msg583"> + <trans-unit id="_msg587"> <source xml:space="preserve">Permissions</source> - <context-group purpose="location"><context context-type="linenumber">1041</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1151</context></context-group> </trans-unit> - <trans-unit id="_msg584"> + <trans-unit id="_msg588"> <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> + <context-group purpose="location"><context context-type="linenumber">1174</context></context-group> </trans-unit> - <trans-unit id="_msg585"> + <trans-unit id="_msg589"> <source xml:space="preserve">Direction/Type</source> - <context-group purpose="location"><context context-type="linenumber">1067</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1177</context></context-group> </trans-unit> - <trans-unit id="_msg586"> + <trans-unit id="_msg590"> + <source xml:space="preserve">The BIP324 session ID string in hex.</source> + <context-group purpose="location"><context context-type="linenumber">1226</context></context-group> + </trans-unit> + <trans-unit id="_msg591"> <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">1142</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1252</context></context-group> </trans-unit> - <trans-unit id="_msg587"> + <trans-unit id="_msg592"> <source xml:space="preserve">Services</source> - <context-group purpose="location"><context context-type="linenumber">1214</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1324</context></context-group> </trans-unit> - <trans-unit id="_msg588"> + <trans-unit id="_msg593"> <source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source> - <context-group purpose="location"><context context-type="linenumber">1266</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1376</context></context-group> </trans-unit> - <trans-unit id="_msg589"> + <trans-unit id="_msg594"> <source xml:space="preserve">High Bandwidth</source> - <context-group purpose="location"><context context-type="linenumber">1269</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1379</context></context-group> </trans-unit> - <trans-unit id="_msg590"> + <trans-unit id="_msg595"> <source xml:space="preserve">Connection Time</source> - <context-group purpose="location"><context context-type="linenumber">1361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1471</context></context-group> </trans-unit> - <trans-unit id="_msg591"> + <trans-unit id="_msg596"> <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">1384</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1494</context></context-group> </trans-unit> - <trans-unit id="_msg592"> + <trans-unit id="_msg597"> <source xml:space="preserve">Last Block</source> - <context-group purpose="location"><context context-type="linenumber">1387</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1497</context></context-group> </trans-unit> - <trans-unit id="_msg593"> + <trans-unit id="_msg598"> <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">1410</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1520</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="_msg594"> + <trans-unit id="_msg599"> <source xml:space="preserve">Last Send</source> - <context-group purpose="location"><context context-type="linenumber">1436</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1546</context></context-group> </trans-unit> - <trans-unit id="_msg595"> + <trans-unit id="_msg600"> <source xml:space="preserve">Last Receive</source> - <context-group purpose="location"><context context-type="linenumber">1459</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1569</context></context-group> </trans-unit> - <trans-unit id="_msg596"> + <trans-unit id="_msg601"> <source xml:space="preserve">Ping Time</source> - <context-group purpose="location"><context context-type="linenumber">1528</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1638</context></context-group> </trans-unit> - <trans-unit id="_msg597"> + <trans-unit id="_msg602"> <source xml:space="preserve">The duration of a currently outstanding ping.</source> - <context-group purpose="location"><context context-type="linenumber">1551</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1661</context></context-group> </trans-unit> - <trans-unit id="_msg598"> + <trans-unit id="_msg603"> <source xml:space="preserve">Ping Wait</source> - <context-group purpose="location"><context context-type="linenumber">1554</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1664</context></context-group> </trans-unit> - <trans-unit id="_msg599"> + <trans-unit id="_msg604"> <source xml:space="preserve">Min Ping</source> - <context-group purpose="location"><context context-type="linenumber">1577</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1687</context></context-group> </trans-unit> - <trans-unit id="_msg600"> + <trans-unit id="_msg605"> <source xml:space="preserve">Time Offset</source> - <context-group purpose="location"><context context-type="linenumber">1600</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1710</context></context-group> </trans-unit> - <trans-unit id="_msg601"> + <trans-unit id="_msg606"> <source xml:space="preserve">Last block time</source> - <context-group purpose="location"><context context-type="linenumber">290</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg602"> + <trans-unit id="_msg607"> <source xml:space="preserve">&Open</source> - <context-group purpose="location"><context context-type="linenumber">400</context></context-group> + <context-group purpose="location"><context context-type="linenumber">435</context></context-group> </trans-unit> - <trans-unit id="_msg603"> + <trans-unit id="_msg608"> <source xml:space="preserve">&Console</source> - <context-group purpose="location"><context context-type="linenumber">426</context></context-group> + <context-group purpose="location"><context context-type="linenumber">461</context></context-group> </trans-unit> - <trans-unit id="_msg604"> + <trans-unit id="_msg609"> <source xml:space="preserve">&Network Traffic</source> - <context-group purpose="location"><context context-type="linenumber">613</context></context-group> + <context-group purpose="location"><context context-type="linenumber">648</context></context-group> </trans-unit> - <trans-unit id="_msg605"> + <trans-unit id="_msg610"> <source xml:space="preserve">Totals</source> - <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + <context-group purpose="location"><context context-type="linenumber">716</context></context-group> </trans-unit> - <trans-unit id="_msg606"> + <trans-unit id="_msg611"> <source xml:space="preserve">Debug log file</source> - <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + <context-group purpose="location"><context context-type="linenumber">425</context></context-group> </trans-unit> - <trans-unit id="_msg607"> + <trans-unit id="_msg612"> <source xml:space="preserve">Clear console</source> - <context-group purpose="location"><context context-type="linenumber">515</context></context-group> + <context-group purpose="location"><context context-type="linenumber">550</context></context-group> </trans-unit> </group> </body></file> <file original="../rpcconsole.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg608"> + <trans-unit id="_msg613"> <source xml:space="preserve">In:</source> - <context-group purpose="location"><context context-type="linenumber">970</context></context-group> + <context-group purpose="location"><context context-type="linenumber">973</context></context-group> </trans-unit> - <trans-unit id="_msg609"> + <trans-unit id="_msg614"> <source xml:space="preserve">Out:</source> - <context-group purpose="location"><context context-type="linenumber">971</context></context-group> + <context-group purpose="location"><context context-type="linenumber">974</context></context-group> </trans-unit> - <trans-unit id="_msg610"> + <trans-unit id="_msg615"> <source xml:space="preserve">Inbound: initiated by peer</source> - <context-group purpose="location"><context context-type="linenumber">496</context></context-group> + <context-group purpose="location"><context context-type="linenumber">497</context></context-group> <note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note> </trans-unit> - <trans-unit id="_msg611"> + <trans-unit id="_msg616"> <source xml:space="preserve">Outbound Full Relay: default</source> - <context-group purpose="location"><context context-type="linenumber">500</context></context-group> + <context-group purpose="location"><context context-type="linenumber">501</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="_msg612"> + <trans-unit id="_msg617"> <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> + <context-group purpose="location"><context context-type="linenumber">504</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="_msg613"> + <trans-unit id="_msg618"> <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> + <context-group purpose="location"><context context-type="linenumber">509</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="_msg614"> + <trans-unit id="_msg619"> <source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source> - <context-group purpose="location"><context context-type="linenumber">514</context></context-group> + <context-group purpose="location"><context context-type="linenumber">515</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="_msg615"> + <trans-unit id="_msg620"> <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> + <context-group purpose="location"><context context-type="linenumber">518</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="_msg616"> + <trans-unit id="_msg621"> <source xml:space="preserve">detecting: peer could be v1 or v2</source> - <context-group purpose="location"><context context-type="linenumber">522</context></context-group> + <context-group purpose="location"><context context-type="linenumber">523</context></context-group> <note annotates="source" from="developer">Explanatory text for "detecting" transport type.</note> </trans-unit> - <trans-unit id="_msg617"> + <trans-unit id="_msg622"> <source xml:space="preserve">v1: unencrypted, plaintext transport protocol</source> - <context-group purpose="location"><context context-type="linenumber">524</context></context-group> + <context-group purpose="location"><context context-type="linenumber">525</context></context-group> <note annotates="source" from="developer">Explanatory text for v1 transport type.</note> </trans-unit> - <trans-unit id="_msg618"> + <trans-unit id="_msg623"> <source xml:space="preserve">v2: BIP324 encrypted transport protocol</source> - <context-group purpose="location"><context context-type="linenumber">526</context></context-group> + <context-group purpose="location"><context context-type="linenumber">527</context></context-group> <note annotates="source" from="developer">Explanatory text for v2 transport type.</note> </trans-unit> - <trans-unit id="_msg619"> + <trans-unit id="_msg624"> <source xml:space="preserve">we selected the peer for high bandwidth relay</source> - <context-group purpose="location"><context context-type="linenumber">530</context></context-group> + <context-group purpose="location"><context context-type="linenumber">531</context></context-group> </trans-unit> - <trans-unit id="_msg620"> + <trans-unit id="_msg625"> <source xml:space="preserve">the peer selected us for high bandwidth relay</source> - <context-group purpose="location"><context context-type="linenumber">531</context></context-group> + <context-group purpose="location"><context context-type="linenumber">532</context></context-group> </trans-unit> - <trans-unit id="_msg621"> + <trans-unit id="_msg626"> <source xml:space="preserve">no high bandwidth relay selected</source> - <context-group purpose="location"><context context-type="linenumber">532</context></context-group> + <context-group purpose="location"><context context-type="linenumber">533</context></context-group> </trans-unit> - <trans-unit id="_msg622"> + <trans-unit id="_msg627"> <source xml:space="preserve">Ctrl++</source> - <context-group purpose="location"><context context-type="linenumber">545</context></context-group> + <context-group purpose="location"><context context-type="linenumber">546</context></context-group> <note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg623"> + <trans-unit id="_msg628"> <source xml:space="preserve">Ctrl+=</source> - <context-group purpose="location"><context context-type="linenumber">547</context></context-group> + <context-group purpose="location"><context context-type="linenumber">548</context></context-group> <note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg624"> + <trans-unit id="_msg629"> <source xml:space="preserve">Ctrl+-</source> - <context-group purpose="location"><context context-type="linenumber">551</context></context-group> + <context-group purpose="location"><context context-type="linenumber">552</context></context-group> <note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg625"> + <trans-unit id="_msg630"> <source xml:space="preserve">Ctrl+_</source> - <context-group purpose="location"><context context-type="linenumber">553</context></context-group> + <context-group purpose="location"><context context-type="linenumber">554</context></context-group> <note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg626"> + <trans-unit id="_msg631"> <source xml:space="preserve">&Copy address</source> - <context-group purpose="location"><context context-type="linenumber">706</context></context-group> + <context-group purpose="location"><context context-type="linenumber">708</context></context-group> <note annotates="source" from="developer">Context menu action to copy the address of a peer.</note> </trans-unit> - <trans-unit id="_msg627"> + <trans-unit id="_msg632"> <source xml:space="preserve">&Disconnect</source> - <context-group purpose="location"><context context-type="linenumber">710</context></context-group> + <context-group purpose="location"><context context-type="linenumber">712</context></context-group> </trans-unit> - <trans-unit id="_msg628"> + <trans-unit id="_msg633"> <source xml:space="preserve">1 &hour</source> - <context-group purpose="location"><context context-type="linenumber">711</context></context-group> + <context-group purpose="location"><context context-type="linenumber">713</context></context-group> </trans-unit> - <trans-unit id="_msg629"> + <trans-unit id="_msg634"> <source xml:space="preserve">1 d&ay</source> - <context-group purpose="location"><context context-type="linenumber">712</context></context-group> + <context-group purpose="location"><context context-type="linenumber">714</context></context-group> </trans-unit> - <trans-unit id="_msg630"> + <trans-unit id="_msg635"> <source xml:space="preserve">1 &week</source> - <context-group purpose="location"><context context-type="linenumber">713</context></context-group> + <context-group purpose="location"><context context-type="linenumber">715</context></context-group> </trans-unit> - <trans-unit id="_msg631"> + <trans-unit id="_msg636"> <source xml:space="preserve">1 &year</source> - <context-group purpose="location"><context context-type="linenumber">714</context></context-group> + <context-group purpose="location"><context context-type="linenumber">716</context></context-group> </trans-unit> - <trans-unit id="_msg632"> + <trans-unit id="_msg637"> <source xml:space="preserve">&Copy IP/Netmask</source> - <context-group purpose="location"><context context-type="linenumber">740</context></context-group> + <context-group purpose="location"><context context-type="linenumber">742</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's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note> </trans-unit> - <trans-unit id="_msg633"> + <trans-unit id="_msg638"> <source xml:space="preserve">&Unban</source> - <context-group purpose="location"><context context-type="linenumber">744</context></context-group> + <context-group purpose="location"><context context-type="linenumber">746</context></context-group> </trans-unit> - <trans-unit id="_msg634"> + <trans-unit id="_msg639"> <source xml:space="preserve">Network activity disabled</source> - <context-group purpose="location"><context context-type="linenumber">974</context></context-group> + <context-group purpose="location"><context context-type="linenumber">977</context></context-group> </trans-unit> - <trans-unit id="_msg635"> + <trans-unit id="_msg640"> + <source xml:space="preserve">None</source> + <context-group purpose="location"><context context-type="linenumber">990</context></context-group> + </trans-unit> + <trans-unit id="_msg641"> <source xml:space="preserve">Executing command without any wallet</source> - <context-group purpose="location"><context context-type="linenumber">1053</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1069</context></context-group> </trans-unit> - <trans-unit id="_msg636"> + <trans-unit id="_msg642"> <source xml:space="preserve">Ctrl+I</source> - <context-group purpose="location"><context context-type="linenumber">1378</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1395</context></context-group> </trans-unit> - <trans-unit id="_msg637"> + <trans-unit id="_msg643"> <source xml:space="preserve">Ctrl+T</source> - <context-group purpose="location"><context context-type="linenumber">1379</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1396</context></context-group> </trans-unit> - <trans-unit id="_msg638"> + <trans-unit id="_msg644"> <source xml:space="preserve">Ctrl+N</source> - <context-group purpose="location"><context context-type="linenumber">1380</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1397</context></context-group> </trans-unit> - <trans-unit id="_msg639"> + <trans-unit id="_msg645"> <source xml:space="preserve">Ctrl+P</source> - <context-group purpose="location"><context context-type="linenumber">1381</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1398</context></context-group> </trans-unit> - <trans-unit id="_msg640"> + <trans-unit id="_msg646"> <source xml:space="preserve">Node window - [%1]</source> - <context-group purpose="location"><context context-type="linenumber">1399</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1416</context></context-group> </trans-unit> - <trans-unit id="_msg641"> + <trans-unit id="_msg647"> <source xml:space="preserve">Executing command using "%1" wallet</source> - <context-group purpose="location"><context context-type="linenumber">1051</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1067</context></context-group> </trans-unit> - <trans-unit id="_msg642"> + <trans-unit id="_msg648"> <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. @@ -2986,124 +3013,124 @@ 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> - <context-group purpose="location"><context context-type="linenumber">904</context></context-group> + <context-group purpose="location"><context context-type="linenumber">906</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="_msg643"> + <trans-unit id="_msg649"> <source xml:space="preserve">Executing…</source> - <context-group purpose="location"><context context-type="linenumber">1061</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1077</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="_msg644"> + <trans-unit id="_msg650"> <source xml:space="preserve">(peer: %1)</source> - <context-group purpose="location"><context context-type="linenumber">1179</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1195</context></context-group> </trans-unit> - <trans-unit id="_msg645"> + <trans-unit id="_msg651"> <source xml:space="preserve">via %1</source> - <context-group purpose="location"><context context-type="linenumber">1181</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1197</context></context-group> </trans-unit> </group> </body></file> <file original="../rpcconsole.h" datatype="c" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg646"> + <trans-unit id="_msg652"> <source xml:space="preserve">Yes</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="_msg647"> + <trans-unit id="_msg653"> <source xml:space="preserve">No</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="_msg648"> + <trans-unit id="_msg654"> <source xml:space="preserve">To</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="_msg649"> + <trans-unit id="_msg655"> <source xml:space="preserve">From</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="_msg650"> + <trans-unit id="_msg656"> <source xml:space="preserve">Ban for</source> - <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg651"> + <trans-unit id="_msg657"> <source xml:space="preserve">Never</source> - <context-group purpose="location"><context context-type="linenumber">189</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg652"> + <trans-unit id="_msg658"> <source xml:space="preserve">Unknown</source> - <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> </group> </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="_msg653"> + <trans-unit id="_msg659"> <source xml:space="preserve">&Amount:</source> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg654"> + <trans-unit id="_msg660"> <source xml:space="preserve">&Label:</source> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg655"> + <trans-unit id="_msg661"> <source xml:space="preserve">&Message:</source> <context-group purpose="location"><context context-type="linenumber">53</context></context-group> </trans-unit> - <trans-unit id="_msg656"> + <trans-unit id="_msg662"> <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="_msg657"> + <trans-unit id="_msg663"> <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="_msg658"> + <trans-unit id="_msg664"> <source xml:space="preserve">Use this form to request payments. All fields are <b>optional</b>.</source> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg659"> + <trans-unit id="_msg665"> <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="_msg660"> + <trans-unit id="_msg666"> <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="_msg661"> + <trans-unit id="_msg667"> <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="_msg662"> + <trans-unit id="_msg668"> <source xml:space="preserve">&Create new receiving address</source> <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg663"> + <trans-unit id="_msg669"> <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="_msg664"> + <trans-unit id="_msg670"> <source xml:space="preserve">Clear</source> <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg665"> + <trans-unit id="_msg671"> <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="_msg666"> + <trans-unit id="_msg672"> <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="_msg667"> + <trans-unit id="_msg673"> <source xml:space="preserve">Show</source> <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg668"> + <trans-unit id="_msg674"> <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="_msg669"> + <trans-unit id="_msg675"> <source xml:space="preserve">Remove</source> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> @@ -3111,63 +3138,63 @@ 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="_msg670"> + <trans-unit id="_msg676"> <source xml:space="preserve">Copy &URI</source> <context-group purpose="location"><context context-type="linenumber">46</context></context-group> </trans-unit> - <trans-unit id="_msg671"> + <trans-unit id="_msg677"> <source xml:space="preserve">&Copy address</source> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg672"> + <trans-unit id="_msg678"> <source xml:space="preserve">Copy &label</source> <context-group purpose="location"><context context-type="linenumber">48</context></context-group> </trans-unit> - <trans-unit id="_msg673"> + <trans-unit id="_msg679"> <source xml:space="preserve">Copy &message</source> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg674"> + <trans-unit id="_msg680"> <source xml:space="preserve">Copy &amount</source> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg675"> + <trans-unit id="_msg681"> <source xml:space="preserve">Base58 (Legacy)</source> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg676"> + <trans-unit id="_msg682"> <source xml:space="preserve">Not recommended due to higher fees and less protection against typos.</source> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg677"> + <trans-unit id="_msg683"> <source xml:space="preserve">Base58 (P2SH-SegWit)</source> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg678"> + <trans-unit id="_msg684"> <source xml:space="preserve">Generates an address compatible with older wallets.</source> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg679"> + <trans-unit id="_msg685"> <source xml:space="preserve">Bech32 (SegWit)</source> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg680"> + <trans-unit id="_msg686"> <source xml:space="preserve">Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg681"> + <trans-unit id="_msg687"> <source xml:space="preserve">Bech32m (Taproot)</source> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg682"> + <trans-unit id="_msg688"> <source xml:space="preserve">Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg683"> + <trans-unit id="_msg689"> <source xml:space="preserve">Could not unlock wallet.</source> <context-group purpose="location"><context context-type="linenumber">175</context></context-group> </trans-unit> - <trans-unit id="_msg684"> + <trans-unit id="_msg690"> <source xml:space="preserve">Could not generate new %1 address</source> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> @@ -3175,51 +3202,51 @@ For more information on using this console, type %6. </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="_msg685"> + <trans-unit id="_msg691"> <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="_msg686"> + <trans-unit id="_msg692"> <source xml:space="preserve">Address:</source> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg687"> + <trans-unit id="_msg693"> <source xml:space="preserve">Amount:</source> <context-group purpose="location"><context context-type="linenumber">119</context></context-group> </trans-unit> - <trans-unit id="_msg688"> + <trans-unit id="_msg694"> <source xml:space="preserve">Label:</source> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg689"> + <trans-unit id="_msg695"> <source xml:space="preserve">Message:</source> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg690"> + <trans-unit id="_msg696"> <source xml:space="preserve">Wallet:</source> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg691"> + <trans-unit id="_msg697"> <source xml:space="preserve">Copy &URI</source> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg692"> + <trans-unit id="_msg698"> <source xml:space="preserve">Copy &Address</source> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg693"> + <trans-unit id="_msg699"> <source xml:space="preserve">&Verify</source> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg694"> + <trans-unit id="_msg700"> <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="_msg695"> + <trans-unit id="_msg701"> <source xml:space="preserve">&Save Image…</source> <context-group purpose="location"><context context-type="linenumber">273</context></context-group> </trans-unit> - <trans-unit id="_msg696"> + <trans-unit id="_msg702"> <source xml:space="preserve">Payment information</source> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> </trans-unit> @@ -3227,190 +3254,190 @@ 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="_msg697"> + <trans-unit id="_msg703"> <source xml:space="preserve">Request payment to %1</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> </group> </body></file> <file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel"> - <trans-unit id="_msg698"> + <trans-unit id="_msg704"> <source xml:space="preserve">Date</source> - <context-group purpose="location"><context context-type="linenumber">32</context></context-group> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg699"> + <trans-unit id="_msg705"> <source xml:space="preserve">Label</source> - <context-group purpose="location"><context context-type="linenumber">32</context></context-group> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg700"> + <trans-unit id="_msg706"> <source xml:space="preserve">Message</source> - <context-group purpose="location"><context context-type="linenumber">32</context></context-group> + <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg701"> + <trans-unit id="_msg707"> <source xml:space="preserve">(no label)</source> - <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + <context-group purpose="location"><context context-type="linenumber">72</context></context-group> </trans-unit> - <trans-unit id="_msg702"> + <trans-unit id="_msg708"> <source xml:space="preserve">(no message)</source> - <context-group purpose="location"><context context-type="linenumber">79</context></context-group> + <context-group purpose="location"><context context-type="linenumber">81</context></context-group> </trans-unit> - <trans-unit id="_msg703"> + <trans-unit id="_msg709"> <source xml:space="preserve">(no amount requested)</source> - <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + <context-group purpose="location"><context context-type="linenumber">89</context></context-group> </trans-unit> - <trans-unit id="_msg704"> + <trans-unit id="_msg710"> <source xml:space="preserve">Requested</source> - <context-group purpose="location"><context context-type="linenumber">130</context></context-group> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> </group> </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="_msg705"> + <trans-unit id="_msg711"> <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">762</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">763</context></context-group> </trans-unit> - <trans-unit id="_msg706"> + <trans-unit id="_msg712"> <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="_msg707"> + <trans-unit id="_msg713"> <source xml:space="preserve">automatically selected</source> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg708"> + <trans-unit id="_msg714"> <source xml:space="preserve">Insufficient funds!</source> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg709"> + <trans-unit id="_msg715"> <source xml:space="preserve">Quantity:</source> <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg710"> + <trans-unit id="_msg716"> <source xml:space="preserve">Bytes:</source> <context-group purpose="location"><context context-type="linenumber">266</context></context-group> </trans-unit> - <trans-unit id="_msg711"> + <trans-unit id="_msg717"> <source xml:space="preserve">Amount:</source> <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> - <trans-unit id="_msg712"> + <trans-unit id="_msg718"> <source xml:space="preserve">Fee:</source> <context-group purpose="location"><context context-type="linenumber">365</context></context-group> </trans-unit> - <trans-unit id="_msg713"> + <trans-unit id="_msg719"> <source xml:space="preserve">After Fee:</source> <context-group purpose="location"><context context-type="linenumber">419</context></context-group> </trans-unit> - <trans-unit id="_msg714"> + <trans-unit id="_msg720"> <source xml:space="preserve">Change:</source> <context-group purpose="location"><context context-type="linenumber">451</context></context-group> </trans-unit> - <trans-unit id="_msg715"> + <trans-unit id="_msg721"> <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">495</context></context-group> </trans-unit> - <trans-unit id="_msg716"> + <trans-unit id="_msg722"> <source xml:space="preserve">Custom change address</source> <context-group purpose="location"><context context-type="linenumber">498</context></context-group> </trans-unit> - <trans-unit id="_msg717"> + <trans-unit id="_msg723"> <source xml:space="preserve">Transaction Fee:</source> <context-group purpose="location"><context context-type="linenumber">704</context></context-group> </trans-unit> - <trans-unit id="_msg718"> + <trans-unit id="_msg724"> <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">742</context></context-group> </trans-unit> - <trans-unit id="_msg719"> + <trans-unit id="_msg725"> <source xml:space="preserve">Warning: Fee estimation is currently not possible.</source> <context-group purpose="location"><context context-type="linenumber">751</context></context-group> </trans-unit> - <trans-unit id="_msg720"> + <trans-unit id="_msg726"> <source xml:space="preserve">per kilobyte</source> <context-group purpose="location"><context context-type="linenumber">833</context></context-group> </trans-unit> - <trans-unit id="_msg721"> + <trans-unit id="_msg727"> <source xml:space="preserve">Hide</source> <context-group purpose="location"><context context-type="linenumber">780</context></context-group> </trans-unit> - <trans-unit id="_msg722"> + <trans-unit id="_msg728"> <source xml:space="preserve">Recommended:</source> <context-group purpose="location"><context context-type="linenumber">892</context></context-group> </trans-unit> - <trans-unit id="_msg723"> + <trans-unit id="_msg729"> <source xml:space="preserve">Custom:</source> <context-group purpose="location"><context context-type="linenumber">922</context></context-group> </trans-unit> - <trans-unit id="_msg724"> + <trans-unit id="_msg730"> <source xml:space="preserve">Send to multiple recipients at once</source> <context-group purpose="location"><context context-type="linenumber">1137</context></context-group> </trans-unit> - <trans-unit id="_msg725"> + <trans-unit id="_msg731"> <source xml:space="preserve">Add &Recipient</source> <context-group purpose="location"><context context-type="linenumber">1140</context></context-group> </trans-unit> - <trans-unit id="_msg726"> + <trans-unit id="_msg732"> <source xml:space="preserve">Clear all fields of the form.</source> <context-group purpose="location"><context context-type="linenumber">1120</context></context-group> </trans-unit> - <trans-unit id="_msg727"> + <trans-unit id="_msg733"> <source xml:space="preserve">Inputs…</source> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg728"> + <trans-unit id="_msg734"> <source xml:space="preserve">Choose…</source> <context-group purpose="location"><context context-type="linenumber">718</context></context-group> </trans-unit> - <trans-unit id="_msg729"> + <trans-unit id="_msg735"> <source xml:space="preserve">Hide transaction fee settings</source> <context-group purpose="location"><context context-type="linenumber">777</context></context-group> </trans-unit> - <trans-unit id="_msg730"> + <trans-unit id="_msg736"> <source xml:space="preserve">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> <context-group purpose="location"><context context-type="linenumber">828</context></context-group> </trans-unit> - <trans-unit id="_msg731"> + <trans-unit id="_msg737"> <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">863</context></context-group> </trans-unit> - <trans-unit id="_msg732"> + <trans-unit id="_msg738"> <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">866</context></context-group> </trans-unit> - <trans-unit id="_msg733"> + <trans-unit id="_msg739"> <source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source> <context-group purpose="location"><context context-type="linenumber">971</context></context-group> </trans-unit> - <trans-unit id="_msg734"> + <trans-unit id="_msg740"> <source xml:space="preserve">Confirmation time target:</source> <context-group purpose="location"><context context-type="linenumber">997</context></context-group> </trans-unit> - <trans-unit id="_msg735"> + <trans-unit id="_msg741"> <source xml:space="preserve">Enable Replace-By-Fee</source> <context-group purpose="location"><context context-type="linenumber">1055</context></context-group> </trans-unit> - <trans-unit id="_msg736"> + <trans-unit id="_msg742"> <source xml:space="preserve">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> <context-group purpose="location"><context context-type="linenumber">1058</context></context-group> </trans-unit> - <trans-unit id="_msg737"> + <trans-unit id="_msg743"> <source xml:space="preserve">Clear &All</source> <context-group purpose="location"><context context-type="linenumber">1123</context></context-group> </trans-unit> - <trans-unit id="_msg738"> + <trans-unit id="_msg744"> <source xml:space="preserve">Balance:</source> <context-group purpose="location"><context context-type="linenumber">1178</context></context-group> </trans-unit> - <trans-unit id="_msg739"> + <trans-unit id="_msg745"> <source xml:space="preserve">Confirm the send action</source> <context-group purpose="location"><context context-type="linenumber">1094</context></context-group> </trans-unit> - <trans-unit id="_msg740"> + <trans-unit id="_msg746"> <source xml:space="preserve">S&end</source> <context-group purpose="location"><context context-type="linenumber">1097</context></context-group> </trans-unit> @@ -3418,300 +3445,300 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> - <trans-unit id="_msg741"> + <trans-unit id="_msg747"> <source xml:space="preserve">Copy quantity</source> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg742"> + <trans-unit id="_msg748"> <source xml:space="preserve">Copy amount</source> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg743"> + <trans-unit id="_msg749"> <source xml:space="preserve">Copy fee</source> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg744"> + <trans-unit id="_msg750"> <source xml:space="preserve">Copy after fee</source> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg745"> + <trans-unit id="_msg751"> <source xml:space="preserve">Copy bytes</source> <context-group purpose="location"><context context-type="linenumber">99</context></context-group> </trans-unit> - <trans-unit id="_msg746"> + <trans-unit id="_msg752"> <source xml:space="preserve">Copy change</source> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg747"> + <trans-unit id="_msg753"> <source xml:space="preserve">%1 (%2 blocks)</source> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg748"> + <trans-unit id="_msg754"> <source xml:space="preserve">Sign on device</source> <context-group purpose="location"><context context-type="linenumber">202</context></context-group> <note annotates="source" from="developer">"device" usually means a hardware wallet.</note> </trans-unit> - <trans-unit id="_msg749"> + <trans-unit id="_msg755"> <source xml:space="preserve">Connect your hardware wallet first.</source> <context-group purpose="location"><context context-type="linenumber">205</context></context-group> </trans-unit> - <trans-unit id="_msg750"> + <trans-unit id="_msg756"> <source xml:space="preserve">Set external signer script path in Options -> Wallet</source> <context-group purpose="location"><context context-type="linenumber">209</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg751"> + <trans-unit id="_msg757"> <source xml:space="preserve">Cr&eate Unsigned</source> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg752"> + <trans-unit id="_msg758"> <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">213</context></context-group> </trans-unit> - <trans-unit id="_msg753"> + <trans-unit id="_msg759"> <source xml:space="preserve">%1 to '%2'</source> <context-group purpose="location"><context context-type="linenumber">316</context></context-group> </trans-unit> - <trans-unit id="_msg754"> + <trans-unit id="_msg760"> <source xml:space="preserve">%1 to %2</source> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg755"> + <trans-unit id="_msg761"> <source xml:space="preserve">To review recipient list click "Show Details…"</source> <context-group purpose="location"><context context-type="linenumber">388</context></context-group> </trans-unit> - <trans-unit id="_msg756"> + <trans-unit id="_msg762"> <source xml:space="preserve">Sign failed</source> - <context-group purpose="location"><context context-type="linenumber">450</context></context-group> + <context-group purpose="location"><context context-type="linenumber">451</context></context-group> </trans-unit> - <trans-unit id="_msg757"> + <trans-unit id="_msg763"> <source xml:space="preserve">External signer not found</source> - <context-group purpose="location"><context context-type="linenumber">455</context></context-group> + <context-group purpose="location"><context context-type="linenumber">456</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg758"> + <trans-unit id="_msg764"> <source xml:space="preserve">External signer failure</source> - <context-group purpose="location"><context context-type="linenumber">461</context></context-group> + <context-group purpose="location"><context context-type="linenumber">462</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg759"> + <trans-unit id="_msg765"> <source xml:space="preserve">Save Transaction Data</source> - <context-group purpose="location"><context context-type="linenumber">425</context></context-group> + <context-group purpose="location"><context context-type="linenumber">426</context></context-group> </trans-unit> - <trans-unit id="_msg760"> + <trans-unit id="_msg766"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> - <context-group purpose="location"><context context-type="linenumber">427</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="_msg761"> + <trans-unit id="_msg767"> <source xml:space="preserve">PSBT saved</source> - <context-group purpose="location"><context context-type="linenumber">435</context></context-group> + <context-group purpose="location"><context context-type="linenumber">436</context></context-group> <note annotates="source" from="developer">Popup message when a PSBT has been saved to a file</note> </trans-unit> - <trans-unit id="_msg762"> + <trans-unit id="_msg768"> <source xml:space="preserve">External balance:</source> - <context-group purpose="location"><context context-type="linenumber">708</context></context-group> + <context-group purpose="location"><context context-type="linenumber">709</context></context-group> </trans-unit> - <trans-unit id="_msg763"> + <trans-unit id="_msg769"> <source xml:space="preserve">or</source> <context-group purpose="location"><context context-type="linenumber">384</context></context-group> </trans-unit> - <trans-unit id="_msg764"> + <trans-unit id="_msg770"> <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">366</context></context-group> </trans-unit> - <trans-unit id="_msg765"> + <trans-unit id="_msg771"> <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">335</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="_msg766"> + <trans-unit id="_msg772"> <source xml:space="preserve">%1 from wallet '%2'</source> <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg767"> + <trans-unit id="_msg773"> <source xml:space="preserve">Do you want to create this transaction?</source> <context-group purpose="location"><context context-type="linenumber">329</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="_msg768"> + <trans-unit id="_msg774"> <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">340</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="_msg769"> + <trans-unit id="_msg775"> <source xml:space="preserve">Please, review your transaction.</source> <context-group purpose="location"><context context-type="linenumber">343</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="_msg770"> + <trans-unit id="_msg776"> <source xml:space="preserve">Transaction fee</source> <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg771"> + <trans-unit id="_msg777"> <source xml:space="preserve">%1 kvB</source> <context-group purpose="location"><context context-type="linenumber">356</context></context-group> <context-group><context context-type="x-gettext-msgctxt">PSBT transaction creation</context></context-group> <note annotates="source" from="developer">When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with "virtual size" of the transaction displayed for context</note> </trans-unit> - <trans-unit id="_msg772"> + <trans-unit id="_msg778"> <source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source> <context-group purpose="location"><context context-type="linenumber">368</context></context-group> </trans-unit> - <trans-unit id="_msg773"> + <trans-unit id="_msg779"> <source xml:space="preserve">Total Amount</source> <context-group purpose="location"><context context-type="linenumber">381</context></context-group> </trans-unit> - <trans-unit id="_msg774"> + <trans-unit id="_msg780"> <source xml:space="preserve">Unsigned Transaction</source> <context-group purpose="location"><context context-type="linenumber">405</context></context-group> <context-group><context context-type="x-gettext-msgctxt">PSBT copied</context></context-group> <note annotates="source" from="developer">Caption of "PSBT has been copied" messagebox</note> </trans-unit> - <trans-unit id="_msg775"> + <trans-unit id="_msg781"> <source xml:space="preserve">The PSBT has been copied to the clipboard. You can also save it.</source> <context-group purpose="location"><context context-type="linenumber">406</context></context-group> </trans-unit> - <trans-unit id="_msg776"> + <trans-unit id="_msg782"> <source xml:space="preserve">PSBT saved to disk</source> - <context-group purpose="location"><context context-type="linenumber">435</context></context-group> + <context-group purpose="location"><context context-type="linenumber">436</context></context-group> </trans-unit> - <trans-unit id="_msg777"> + <trans-unit id="_msg783"> <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">485</context></context-group> </trans-unit> - <trans-unit id="_msg778"> + <trans-unit id="_msg784"> <source xml:space="preserve">Watch-only balance:</source> - <context-group purpose="location"><context context-type="linenumber">711</context></context-group> + <context-group purpose="location"><context context-type="linenumber">712</context></context-group> </trans-unit> - <trans-unit id="_msg779"> + <trans-unit id="_msg785"> <source xml:space="preserve">The recipient address is not valid. Please recheck.</source> - <context-group purpose="location"><context context-type="linenumber">735</context></context-group> + <context-group purpose="location"><context context-type="linenumber">736</context></context-group> </trans-unit> - <trans-unit id="_msg780"> + <trans-unit id="_msg786"> <source xml:space="preserve">The amount to pay must be larger than 0.</source> - <context-group purpose="location"><context context-type="linenumber">738</context></context-group> + <context-group purpose="location"><context context-type="linenumber">739</context></context-group> </trans-unit> - <trans-unit id="_msg781"> + <trans-unit id="_msg787"> <source xml:space="preserve">The amount exceeds your balance.</source> - <context-group purpose="location"><context context-type="linenumber">741</context></context-group> + <context-group purpose="location"><context context-type="linenumber">742</context></context-group> </trans-unit> - <trans-unit id="_msg782"> + <trans-unit id="_msg788"> <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">744</context></context-group> + <context-group purpose="location"><context context-type="linenumber">745</context></context-group> </trans-unit> - <trans-unit id="_msg783"> + <trans-unit id="_msg789"> <source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source> - <context-group purpose="location"><context context-type="linenumber">747</context></context-group> + <context-group purpose="location"><context context-type="linenumber">748</context></context-group> </trans-unit> - <trans-unit id="_msg784"> + <trans-unit id="_msg790"> <source xml:space="preserve">Transaction creation failed!</source> - <context-group purpose="location"><context context-type="linenumber">750</context></context-group> + <context-group purpose="location"><context context-type="linenumber">751</context></context-group> </trans-unit> - <trans-unit id="_msg785"> + <trans-unit id="_msg791"> <source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source> - <context-group purpose="location"><context context-type="linenumber">754</context></context-group> + <context-group purpose="location"><context context-type="linenumber">755</context></context-group> </trans-unit> - <trans-unit id="_msg786"> + <trans-unit id="_msg792"> <source xml:space="preserve">%1/kvB</source> - <context-group purpose="location"><context context-type="linenumber">833</context></context-group> - <context-group purpose="location"><context context-type="linenumber">868</context></context-group> + <context-group purpose="location"><context context-type="linenumber">834</context></context-group> + <context-group purpose="location"><context context-type="linenumber">869</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">882</context></context-group> - <trans-unit id="_msg787[0]"> + <context-group purpose="location"><context context-type="linenumber">883</context></context-group> + <trans-unit id="_msg793[0]"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> </trans-unit> - <trans-unit id="_msg787[1]"> + <trans-unit id="_msg793[1]"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> </trans-unit> </group> - <trans-unit id="_msg788"> + <trans-unit id="_msg794"> <source xml:space="preserve">Warning: Invalid Bitcoin address</source> - <context-group purpose="location"><context context-type="linenumber">977</context></context-group> + <context-group purpose="location"><context context-type="linenumber">978</context></context-group> </trans-unit> - <trans-unit id="_msg789"> + <trans-unit id="_msg795"> <source xml:space="preserve">Warning: Unknown change address</source> - <context-group purpose="location"><context context-type="linenumber">982</context></context-group> + <context-group purpose="location"><context context-type="linenumber">983</context></context-group> </trans-unit> - <trans-unit id="_msg790"> + <trans-unit id="_msg796"> <source xml:space="preserve">Confirm custom change address</source> - <context-group purpose="location"><context context-type="linenumber">985</context></context-group> + <context-group purpose="location"><context context-type="linenumber">986</context></context-group> </trans-unit> - <trans-unit id="_msg791"> + <trans-unit id="_msg797"> <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">985</context></context-group> + <context-group purpose="location"><context context-type="linenumber">986</context></context-group> </trans-unit> - <trans-unit id="_msg792"> + <trans-unit id="_msg798"> <source xml:space="preserve">(no label)</source> - <context-group purpose="location"><context context-type="linenumber">1006</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1007</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="_msg793"> + <trans-unit id="_msg799"> <source xml:space="preserve">A&mount:</source> <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg794"> + <trans-unit id="_msg800"> <source xml:space="preserve">Pay &To:</source> <context-group purpose="location"><context context-type="linenumber">35</context></context-group> </trans-unit> - <trans-unit id="_msg795"> + <trans-unit id="_msg801"> <source xml:space="preserve">&Label:</source> <context-group purpose="location"><context context-type="linenumber">128</context></context-group> </trans-unit> - <trans-unit id="_msg796"> + <trans-unit id="_msg802"> <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="_msg797"> + <trans-unit id="_msg803"> <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="_msg798"> + <trans-unit id="_msg804"> <source xml:space="preserve">Alt+A</source> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg799"> + <trans-unit id="_msg805"> <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="_msg800"> + <trans-unit id="_msg806"> <source xml:space="preserve">Alt+P</source> <context-group purpose="location"><context context-type="linenumber">99</context></context-group> </trans-unit> - <trans-unit id="_msg801"> + <trans-unit id="_msg807"> <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="_msg802"> + <trans-unit id="_msg808"> <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="_msg803"> + <trans-unit id="_msg809"> <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="_msg804"> + <trans-unit id="_msg810"> <source xml:space="preserve">S&ubtract fee from amount</source> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg805"> + <trans-unit id="_msg811"> <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="_msg806"> + <trans-unit id="_msg812"> <source xml:space="preserve">Message:</source> <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg807"> + <trans-unit id="_msg813"> <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="_msg808"> + <trans-unit id="_msg814"> <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> @@ -3719,11 +3746,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../sendcoinsdialog.h" datatype="c" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog"> - <trans-unit id="_msg809"> + <trans-unit id="_msg815"> <source xml:space="preserve">Send</source> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg810"> + <trans-unit id="_msg816"> <source xml:space="preserve">Create Unsigned</source> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> @@ -3731,105 +3758,105 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "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="_msg811"> + <trans-unit id="_msg817"> <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="_msg812"> + <trans-unit id="_msg818"> <source xml:space="preserve">&Sign Message</source> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg813"> - <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> + <trans-unit id="_msg819"> + <source xml:space="preserve">You can sign messages/agreements with your legacy (P2PKH) 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="_msg814"> + <trans-unit id="_msg820"> <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="_msg815"> + <trans-unit id="_msg821"> <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="_msg816"> + <trans-unit id="_msg822"> <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="_msg817"> + <trans-unit id="_msg823"> <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="_msg818"> + <trans-unit id="_msg824"> <source xml:space="preserve">Alt+P</source> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg819"> + <trans-unit id="_msg825"> <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="_msg820"> + <trans-unit id="_msg826"> <source xml:space="preserve">Signature</source> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg821"> + <trans-unit id="_msg827"> <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="_msg822"> + <trans-unit id="_msg828"> <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="_msg823"> + <trans-unit id="_msg829"> <source xml:space="preserve">Sign &Message</source> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg824"> + <trans-unit id="_msg830"> <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="_msg825"> + <trans-unit id="_msg831"> <source xml:space="preserve">Clear &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="_msg826"> + <trans-unit id="_msg832"> <source xml:space="preserve">&Verify Message</source> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg827"> + <trans-unit id="_msg833"> <source xml:space="preserve">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> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg828"> + <trans-unit id="_msg834"> <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="_msg829"> + <trans-unit id="_msg835"> <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="_msg830"> + <trans-unit id="_msg836"> <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="_msg831"> + <trans-unit id="_msg837"> <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="_msg832"> + <trans-unit id="_msg838"> <source xml:space="preserve">Verify &Message</source> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg833"> + <trans-unit id="_msg839"> <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="_msg834"> + <trans-unit id="_msg840"> <source xml:space="preserve">Click "Sign Message" to generate signature</source> <context-group purpose="location"><context context-type="linenumber">125</context></context-group> </trans-unit> @@ -3837,81 +3864,79 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> - <trans-unit id="_msg835"> + <trans-unit id="_msg841"> <source xml:space="preserve">The entered address is invalid.</source> - <context-group purpose="location"><context context-type="linenumber">119</context></context-group> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> - <trans-unit id="_msg836"> + <trans-unit id="_msg842"> <source xml:space="preserve">Please check the address and try again.</source> - <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> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> - <trans-unit id="_msg837"> - <source xml:space="preserve">The entered address does not refer to a key.</source> - <context-group purpose="location"><context context-type="linenumber">126</context></context-group> + <trans-unit id="_msg843"> + <source xml:space="preserve">The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.</source> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg838"> + <trans-unit id="_msg844"> <source xml:space="preserve">Wallet unlock was cancelled.</source> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + <context-group purpose="location"><context context-type="linenumber">135</context></context-group> </trans-unit> - <trans-unit id="_msg839"> + <trans-unit id="_msg845"> <source xml:space="preserve">No error</source> - <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg840"> + <trans-unit id="_msg846"> <source xml:space="preserve">Private key for the entered address is not available.</source> - <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg841"> + <trans-unit id="_msg847"> <source xml:space="preserve">Message signing failed.</source> - <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg842"> + <trans-unit id="_msg848"> <source xml:space="preserve">Message signed.</source> - <context-group purpose="location"><context context-type="linenumber">163</context></context-group> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg843"> + <trans-unit id="_msg849"> <source xml:space="preserve">The signature could not be decoded.</source> - <context-group purpose="location"><context context-type="linenumber">232</context></context-group> + <context-group purpose="location"><context context-type="linenumber">230</context></context-group> </trans-unit> - <trans-unit id="_msg844"> + <trans-unit id="_msg850"> <source xml:space="preserve">Please check the signature and try again.</source> - <context-group purpose="location"><context context-type="linenumber">233</context></context-group> - <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg845"> + <trans-unit id="_msg851"> <source xml:space="preserve">The signature did not match the message digest.</source> - <context-group purpose="location"><context context-type="linenumber">239</context></context-group> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> </trans-unit> - <trans-unit id="_msg846"> + <trans-unit id="_msg852"> <source xml:space="preserve">Message verification failed.</source> - <context-group purpose="location"><context context-type="linenumber">245</context></context-group> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> - <trans-unit id="_msg847"> + <trans-unit id="_msg853"> <source xml:space="preserve">Message verified.</source> - <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + <context-group purpose="location"><context context-type="linenumber">214</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="_msg848"> + <trans-unit id="_msg854"> <source xml:space="preserve">(press q to shutdown and continue later)</source> - <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + <context-group purpose="location"><context context-type="linenumber">175</context></context-group> </trans-unit> - <trans-unit id="_msg849"> + <trans-unit id="_msg855"> <source xml:space="preserve">press q to shutdown</source> - <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + <context-group purpose="location"><context context-type="linenumber">176</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="_msg850"> + <trans-unit id="_msg856"> <source xml:space="preserve">kB/s</source> <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> @@ -3919,194 +3944,194 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiondesc.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDesc"> - <trans-unit id="_msg851"> + <trans-unit id="_msg857"> <source xml:space="preserve">conflicted with a transaction with %1 confirmations</source> - <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + <context-group purpose="location"><context context-type="linenumber">40</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="_msg852"> + <trans-unit id="_msg858"> <source xml:space="preserve">0/unconfirmed, in memory pool</source> - <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + <context-group purpose="location"><context context-type="linenumber">47</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="_msg853"> + <trans-unit id="_msg859"> <source xml:space="preserve">0/unconfirmed, not in memory pool</source> - <context-group purpose="location"><context context-type="linenumber">56</context></context-group> + <context-group purpose="location"><context context-type="linenumber">52</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="_msg854"> + <trans-unit id="_msg860"> <source xml:space="preserve">abandoned</source> - <context-group purpose="location"><context context-type="linenumber">62</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</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="_msg855"> + <trans-unit id="_msg861"> <source xml:space="preserve">%1/unconfirmed</source> - <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + <context-group purpose="location"><context context-type="linenumber">66</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="_msg856"> + <trans-unit id="_msg862"> <source xml:space="preserve">%1 confirmations</source> - <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">71</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="_msg857"> + <trans-unit id="_msg863"> <source xml:space="preserve">Status</source> - <context-group purpose="location"><context context-type="linenumber">125</context></context-group> + <context-group purpose="location"><context context-type="linenumber">121</context></context-group> </trans-unit> - <trans-unit id="_msg858"> + <trans-unit id="_msg864"> <source xml:space="preserve">Date</source> - <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg859"> + <trans-unit id="_msg865"> <source xml:space="preserve">Source</source> - <context-group purpose="location"><context context-type="linenumber">135</context></context-group> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg860"> + <trans-unit id="_msg866"> <source xml:space="preserve">Generated</source> - <context-group purpose="location"><context context-type="linenumber">135</context></context-group> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg861"> + <trans-unit id="_msg867"> <source xml:space="preserve">From</source> - <context-group purpose="location"><context context-type="linenumber">140</context></context-group> - <context-group purpose="location"><context context-type="linenumber">154</context></context-group> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">150</context></context-group> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg862"> + <trans-unit id="_msg868"> <source xml:space="preserve">unknown</source> - <context-group purpose="location"><context context-type="linenumber">154</context></context-group> + <context-group purpose="location"><context context-type="linenumber">150</context></context-group> </trans-unit> - <trans-unit id="_msg863"> + <trans-unit id="_msg869"> <source xml:space="preserve">To</source> - <context-group purpose="location"><context context-type="linenumber">155</context></context-group> - <context-group purpose="location"><context context-type="linenumber">175</context></context-group> - <context-group purpose="location"><context context-type="linenumber">245</context></context-group> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg864"> + <trans-unit id="_msg870"> <source xml:space="preserve">own address</source> - <context-group purpose="location"><context context-type="linenumber">157</context></context-group> - <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg865"> + <trans-unit id="_msg871"> <source xml:space="preserve">watch-only</source> - <context-group purpose="location"><context context-type="linenumber">157</context></context-group> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> - <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg866"> + <trans-unit id="_msg872"> <source xml:space="preserve">label</source> - <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> </trans-unit> - <trans-unit id="_msg867"> + <trans-unit id="_msg873"> <source xml:space="preserve">Credit</source> - <context-group purpose="location"><context context-type="linenumber">195</context></context-group> - <context-group purpose="location"><context context-type="linenumber">207</context></context-group> - <context-group purpose="location"><context context-type="linenumber">261</context></context-group> - <context-group purpose="location"><context context-type="linenumber">291</context></context-group> - <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + <context-group purpose="location"><context context-type="linenumber">257</context></context-group> + <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">347</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">197</context></context-group> - <trans-unit id="_msg868[0]"> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + <trans-unit id="_msg874[0]"> <source xml:space="preserve">matures in %n more block(s)</source> </trans-unit> - <trans-unit id="_msg868[1]"> + <trans-unit id="_msg874[1]"> <source xml:space="preserve">matures in %n more block(s)</source> </trans-unit> </group> - <trans-unit id="_msg869"> + <trans-unit id="_msg875"> <source xml:space="preserve">not accepted</source> - <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + <context-group purpose="location"><context context-type="linenumber">195</context></context-group> </trans-unit> - <trans-unit id="_msg870"> + <trans-unit id="_msg876"> <source xml:space="preserve">Debit</source> - <context-group purpose="location"><context context-type="linenumber">259</context></context-group> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> - <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg871"> + <trans-unit id="_msg877"> <source xml:space="preserve">Total debit</source> - <context-group purpose="location"><context context-type="linenumber">269</context></context-group> + <context-group purpose="location"><context context-type="linenumber">265</context></context-group> </trans-unit> - <trans-unit id="_msg872"> + <trans-unit id="_msg878"> <source xml:space="preserve">Total credit</source> - <context-group purpose="location"><context context-type="linenumber">270</context></context-group> + <context-group purpose="location"><context context-type="linenumber">266</context></context-group> </trans-unit> - <trans-unit id="_msg873"> + <trans-unit id="_msg879"> <source xml:space="preserve">Transaction fee</source> - <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + <context-group purpose="location"><context context-type="linenumber">271</context></context-group> </trans-unit> - <trans-unit id="_msg874"> + <trans-unit id="_msg880"> <source xml:space="preserve">Net amount</source> - <context-group purpose="location"><context context-type="linenumber">297</context></context-group> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> - <trans-unit id="_msg875"> + <trans-unit id="_msg881"> <source xml:space="preserve">Message</source> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> - <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> - <trans-unit id="_msg876"> + <trans-unit id="_msg882"> <source xml:space="preserve">Comment</source> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg877"> + <trans-unit id="_msg883"> <source xml:space="preserve">Transaction ID</source> - <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg878"> + <trans-unit id="_msg884"> <source xml:space="preserve">Transaction total size</source> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg879"> + <trans-unit id="_msg885"> <source xml:space="preserve">Transaction virtual size</source> - <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg880"> + <trans-unit id="_msg886"> <source xml:space="preserve">Output index</source> - <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg881"> + <trans-unit id="_msg887"> <source xml:space="preserve">%1 (Certificate was not verified)</source> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg882"> + <trans-unit id="_msg888"> <source xml:space="preserve">Merchant</source> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg883"> + <trans-unit id="_msg889"> <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 "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> - <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg884"> + <trans-unit id="_msg890"> <source xml:space="preserve">Debug information</source> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg885"> + <trans-unit id="_msg891"> <source xml:space="preserve">Transaction</source> - <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg886"> + <trans-unit id="_msg892"> <source xml:space="preserve">Inputs</source> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> - <trans-unit id="_msg887"> + <trans-unit id="_msg893"> <source xml:space="preserve">Amount</source> - <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> - <trans-unit id="_msg888"> + <trans-unit id="_msg894"> <source xml:space="preserve">true</source> - <context-group purpose="location"><context context-type="linenumber">376</context></context-group> - <context-group purpose="location"><context context-type="linenumber">377</context></context-group> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> - <trans-unit id="_msg889"> + <trans-unit id="_msg895"> <source xml:space="preserve">false</source> - <context-group purpose="location"><context context-type="linenumber">376</context></context-group> - <context-group purpose="location"><context context-type="linenumber">377</context></context-group> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> </group> </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="_msg890"> + <trans-unit id="_msg896"> <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> @@ -4114,7 +4139,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> - <trans-unit id="_msg891"> + <trans-unit id="_msg897"> <source xml:space="preserve">Details for %1</source> <context-group purpose="location"><context context-type="linenumber">18</context></context-group> </trans-unit> @@ -4122,95 +4147,95 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionTableModel"> - <trans-unit id="_msg892"> + <trans-unit id="_msg898"> <source xml:space="preserve">Date</source> <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg893"> + <trans-unit id="_msg899"> <source xml:space="preserve">Type</source> <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg894"> + <trans-unit id="_msg900"> <source xml:space="preserve">Label</source> <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg895"> + <trans-unit id="_msg901"> <source xml:space="preserve">Unconfirmed</source> <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg896"> + <trans-unit id="_msg902"> <source xml:space="preserve">Abandoned</source> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg897"> + <trans-unit id="_msg903"> <source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source> <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg898"> + <trans-unit id="_msg904"> <source xml:space="preserve">Confirmed (%1 confirmations)</source> <context-group purpose="location"><context context-type="linenumber">327</context></context-group> </trans-unit> - <trans-unit id="_msg899"> + <trans-unit id="_msg905"> <source xml:space="preserve">Conflicted</source> <context-group purpose="location"><context context-type="linenumber">330</context></context-group> </trans-unit> - <trans-unit id="_msg900"> + <trans-unit id="_msg906"> <source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source> <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg901"> + <trans-unit id="_msg907"> <source xml:space="preserve">Generated but not accepted</source> <context-group purpose="location"><context context-type="linenumber">336</context></context-group> </trans-unit> - <trans-unit id="_msg902"> + <trans-unit id="_msg908"> <source xml:space="preserve">Received with</source> <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg903"> + <trans-unit id="_msg909"> <source xml:space="preserve">Received from</source> <context-group purpose="location"><context context-type="linenumber">377</context></context-group> </trans-unit> - <trans-unit id="_msg904"> + <trans-unit id="_msg910"> <source xml:space="preserve">Sent to</source> <context-group purpose="location"><context context-type="linenumber">380</context></context-group> </trans-unit> - <trans-unit id="_msg905"> + <trans-unit id="_msg911"> <source xml:space="preserve">Mined</source> <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> - <trans-unit id="_msg906"> + <trans-unit id="_msg912"> <source xml:space="preserve">watch-only</source> <context-group purpose="location"><context context-type="linenumber">410</context></context-group> </trans-unit> - <trans-unit id="_msg907"> + <trans-unit id="_msg913"> <source xml:space="preserve">(n/a)</source> <context-group purpose="location"><context context-type="linenumber">424</context></context-group> </trans-unit> - <trans-unit id="_msg908"> + <trans-unit id="_msg914"> <source xml:space="preserve">(no label)</source> <context-group purpose="location"><context context-type="linenumber">629</context></context-group> </trans-unit> - <trans-unit id="_msg909"> + <trans-unit id="_msg915"> <source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source> <context-group purpose="location"><context context-type="linenumber">668</context></context-group> </trans-unit> - <trans-unit id="_msg910"> + <trans-unit id="_msg916"> <source xml:space="preserve">Date and time that the transaction was received.</source> <context-group purpose="location"><context context-type="linenumber">670</context></context-group> </trans-unit> - <trans-unit id="_msg911"> + <trans-unit id="_msg917"> <source xml:space="preserve">Type of transaction.</source> <context-group purpose="location"><context context-type="linenumber">672</context></context-group> </trans-unit> - <trans-unit id="_msg912"> + <trans-unit id="_msg918"> <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">674</context></context-group> </trans-unit> - <trans-unit id="_msg913"> + <trans-unit id="_msg919"> <source xml:space="preserve">User-defined intent/purpose of the transaction.</source> <context-group purpose="location"><context context-type="linenumber">676</context></context-group> </trans-unit> - <trans-unit id="_msg914"> + <trans-unit id="_msg920"> <source xml:space="preserve">Amount removed from or added to balance.</source> <context-group purpose="location"><context context-type="linenumber">678</context></context-group> </trans-unit> @@ -4218,162 +4243,162 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactionview.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionView"> - <trans-unit id="_msg915"> + <trans-unit id="_msg921"> <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="_msg916"> + <trans-unit id="_msg922"> <source xml:space="preserve">Today</source> <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg917"> + <trans-unit id="_msg923"> <source xml:space="preserve">This week</source> <context-group purpose="location"><context context-type="linenumber">75</context></context-group> </trans-unit> - <trans-unit id="_msg918"> + <trans-unit id="_msg924"> <source xml:space="preserve">This month</source> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg919"> + <trans-unit id="_msg925"> <source xml:space="preserve">Last month</source> <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg920"> + <trans-unit id="_msg926"> <source xml:space="preserve">This year</source> <context-group purpose="location"><context context-type="linenumber">78</context></context-group> </trans-unit> - <trans-unit id="_msg921"> + <trans-unit id="_msg927"> <source xml:space="preserve">Received with</source> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg922"> + <trans-unit id="_msg928"> <source xml:space="preserve">Sent to</source> <context-group purpose="location"><context context-type="linenumber">92</context></context-group> </trans-unit> - <trans-unit id="_msg923"> + <trans-unit id="_msg929"> <source xml:space="preserve">Mined</source> <context-group purpose="location"><context context-type="linenumber">94</context></context-group> </trans-unit> - <trans-unit id="_msg924"> + <trans-unit id="_msg930"> <source xml:space="preserve">Other</source> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg925"> + <trans-unit id="_msg931"> <source xml:space="preserve">Enter address, transaction id, or label to search</source> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg926"> + <trans-unit id="_msg932"> <source xml:space="preserve">Min amount</source> <context-group purpose="location"><context context-type="linenumber">104</context></context-group> </trans-unit> - <trans-unit id="_msg927"> + <trans-unit id="_msg933"> <source xml:space="preserve">Range…</source> <context-group purpose="location"><context context-type="linenumber">79</context></context-group> </trans-unit> - <trans-unit id="_msg928"> + <trans-unit id="_msg934"> <source xml:space="preserve">&Copy address</source> <context-group purpose="location"><context context-type="linenumber">168</context></context-group> </trans-unit> - <trans-unit id="_msg929"> + <trans-unit id="_msg935"> <source xml:space="preserve">Copy &label</source> <context-group purpose="location"><context context-type="linenumber">169</context></context-group> </trans-unit> - <trans-unit id="_msg930"> + <trans-unit id="_msg936"> <source xml:space="preserve">Copy &amount</source> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg931"> + <trans-unit id="_msg937"> <source xml:space="preserve">Copy transaction &ID</source> <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> - <trans-unit id="_msg932"> + <trans-unit id="_msg938"> <source xml:space="preserve">Copy &raw transaction</source> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg933"> + <trans-unit id="_msg939"> <source xml:space="preserve">Copy full transaction &details</source> <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg934"> + <trans-unit id="_msg940"> <source xml:space="preserve">&Show transaction details</source> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg935"> + <trans-unit id="_msg941"> <source xml:space="preserve">Increase transaction &fee</source> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg936"> + <trans-unit id="_msg942"> <source xml:space="preserve">A&bandon transaction</source> <context-group purpose="location"><context context-type="linenumber">179</context></context-group> </trans-unit> - <trans-unit id="_msg937"> + <trans-unit id="_msg943"> <source xml:space="preserve">&Edit address label</source> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg938"> + <trans-unit id="_msg944"> <source xml:space="preserve">Show in %1</source> <context-group purpose="location"><context context-type="linenumber">239</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="_msg939"> + <trans-unit id="_msg945"> <source xml:space="preserve">Export Transaction History</source> <context-group purpose="location"><context context-type="linenumber">358</context></context-group> </trans-unit> - <trans-unit id="_msg940"> + <trans-unit id="_msg946"> <source xml:space="preserve">Comma separated file</source> <context-group purpose="location"><context context-type="linenumber">361</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="_msg941"> + <trans-unit id="_msg947"> <source xml:space="preserve">Confirmed</source> <context-group purpose="location"><context context-type="linenumber">370</context></context-group> </trans-unit> - <trans-unit id="_msg942"> + <trans-unit id="_msg948"> <source xml:space="preserve">Watch-only</source> <context-group purpose="location"><context context-type="linenumber">372</context></context-group> </trans-unit> - <trans-unit id="_msg943"> + <trans-unit id="_msg949"> <source xml:space="preserve">Date</source> <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> - <trans-unit id="_msg944"> + <trans-unit id="_msg950"> <source xml:space="preserve">Type</source> <context-group purpose="location"><context context-type="linenumber">374</context></context-group> </trans-unit> - <trans-unit id="_msg945"> + <trans-unit id="_msg951"> <source xml:space="preserve">Label</source> <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg946"> + <trans-unit id="_msg952"> <source xml:space="preserve">Address</source> <context-group purpose="location"><context context-type="linenumber">376</context></context-group> </trans-unit> - <trans-unit id="_msg947"> + <trans-unit id="_msg953"> <source xml:space="preserve">ID</source> <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> - <trans-unit id="_msg948"> + <trans-unit id="_msg954"> <source xml:space="preserve">Exporting Failed</source> <context-group purpose="location"><context context-type="linenumber">381</context></context-group> </trans-unit> - <trans-unit id="_msg949"> + <trans-unit id="_msg955"> <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">381</context></context-group> </trans-unit> - <trans-unit id="_msg950"> + <trans-unit id="_msg956"> <source xml:space="preserve">Exporting Successful</source> <context-group purpose="location"><context context-type="linenumber">385</context></context-group> </trans-unit> - <trans-unit id="_msg951"> + <trans-unit id="_msg957"> <source xml:space="preserve">The transaction history was successfully saved to %1.</source> <context-group purpose="location"><context context-type="linenumber">385</context></context-group> </trans-unit> - <trans-unit id="_msg952"> + <trans-unit id="_msg958"> <source xml:space="preserve">Range:</source> <context-group purpose="location"><context context-type="linenumber">558</context></context-group> </trans-unit> - <trans-unit id="_msg953"> + <trans-unit id="_msg959"> <source xml:space="preserve">to</source> <context-group purpose="location"><context context-type="linenumber">566</context></context-group> </trans-unit> @@ -4381,39 +4406,39 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../walletframe.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletFrame"> - <trans-unit id="_msg954"> + <trans-unit id="_msg960"> <source xml:space="preserve">No wallet has been loaded. Go to File > 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="_msg955"> + <trans-unit id="_msg961"> <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="_msg956"> + <trans-unit id="_msg962"> <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="_msg957"> + <trans-unit id="_msg963"> <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="_msg958"> + <trans-unit id="_msg964"> <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="_msg959"> + <trans-unit id="_msg965"> <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="_msg960"> + <trans-unit id="_msg966"> <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="_msg961"> + <trans-unit id="_msg967"> <source xml:space="preserve">Unable to decode PSBT</source> <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> @@ -4421,114 +4446,113 @@ Go to File > 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="_msg962"> + <trans-unit id="_msg968"> <source xml:space="preserve">Send Coins</source> - <context-group purpose="location"><context context-type="linenumber">227</context></context-group> - <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> </trans-unit> - <trans-unit id="_msg963"> + <trans-unit id="_msg969"> <source xml:space="preserve">Fee bump error</source> - <context-group purpose="location"><context context-type="linenumber">494</context></context-group> - <context-group purpose="location"><context context-type="linenumber">549</context></context-group> - <context-group purpose="location"><context context-type="linenumber">564</context></context-group> - <context-group purpose="location"><context context-type="linenumber">569</context></context-group> + <context-group purpose="location"><context context-type="linenumber">491</context></context-group> + <context-group purpose="location"><context context-type="linenumber">540</context></context-group> + <context-group purpose="location"><context context-type="linenumber">560</context></context-group> + <context-group purpose="location"><context context-type="linenumber">565</context></context-group> </trans-unit> - <trans-unit id="_msg964"> + <trans-unit id="_msg970"> <source xml:space="preserve">Increasing transaction fee failed</source> - <context-group purpose="location"><context context-type="linenumber">494</context></context-group> + <context-group purpose="location"><context context-type="linenumber">491</context></context-group> </trans-unit> - <trans-unit id="_msg965"> + <trans-unit id="_msg971"> <source xml:space="preserve">Do you want to increase the fee?</source> - <context-group purpose="location"><context context-type="linenumber">501</context></context-group> + <context-group purpose="location"><context context-type="linenumber">498</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="_msg966"> + <trans-unit id="_msg972"> <source xml:space="preserve">Current fee:</source> - <context-group purpose="location"><context context-type="linenumber">505</context></context-group> + <context-group purpose="location"><context context-type="linenumber">502</context></context-group> </trans-unit> - <trans-unit id="_msg967"> + <trans-unit id="_msg973"> <source xml:space="preserve">Increase:</source> - <context-group purpose="location"><context context-type="linenumber">509</context></context-group> + <context-group purpose="location"><context context-type="linenumber">506</context></context-group> </trans-unit> - <trans-unit id="_msg968"> + <trans-unit id="_msg974"> <source xml:space="preserve">New fee:</source> - <context-group purpose="location"><context context-type="linenumber">513</context></context-group> + <context-group purpose="location"><context context-type="linenumber">510</context></context-group> </trans-unit> - <trans-unit id="_msg969"> + <trans-unit id="_msg975"> <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">521</context></context-group> + <context-group purpose="location"><context context-type="linenumber">518</context></context-group> </trans-unit> - <trans-unit id="_msg970"> + <trans-unit id="_msg976"> <source xml:space="preserve">Confirm fee bump</source> - <context-group purpose="location"><context context-type="linenumber">526</context></context-group> + <context-group purpose="location"><context context-type="linenumber">523</context></context-group> </trans-unit> - <trans-unit id="_msg971"> + <trans-unit id="_msg977"> <source xml:space="preserve">Can't draft transaction.</source> - <context-group purpose="location"><context context-type="linenumber">549</context></context-group> + <context-group purpose="location"><context context-type="linenumber">540</context></context-group> </trans-unit> - <trans-unit id="_msg972"> + <trans-unit id="_msg978"> <source xml:space="preserve">PSBT copied</source> - <context-group purpose="location"><context context-type="linenumber">556</context></context-group> + <context-group purpose="location"><context context-type="linenumber">547</context></context-group> </trans-unit> - <trans-unit id="_msg973"> - <source xml:space="preserve">Copied to clipboard</source> - <context-group purpose="location"><context context-type="linenumber">556</context></context-group> - <context-group><context context-type="x-gettext-msgctxt">Fee-bump PSBT saved</context></context-group> + <trans-unit id="_msg979"> + <source xml:space="preserve">Fee-bump PSBT copied to clipboard</source> + <context-group purpose="location"><context context-type="linenumber">547</context></context-group> </trans-unit> - <trans-unit id="_msg974"> + <trans-unit id="_msg980"> <source xml:space="preserve">Can't sign transaction.</source> - <context-group purpose="location"><context context-type="linenumber">564</context></context-group> + <context-group purpose="location"><context context-type="linenumber">560</context></context-group> </trans-unit> - <trans-unit id="_msg975"> + <trans-unit id="_msg981"> <source xml:space="preserve">Could not commit transaction</source> - <context-group purpose="location"><context context-type="linenumber">569</context></context-group> + <context-group purpose="location"><context context-type="linenumber">565</context></context-group> </trans-unit> - <trans-unit id="_msg976"> - <source xml:space="preserve">Can't display address</source> - <context-group purpose="location"><context context-type="linenumber">583</context></context-group> + <trans-unit id="_msg982"> + <source xml:space="preserve">Signer error</source> + <context-group purpose="location"><context context-type="linenumber">578</context></context-group> </trans-unit> - <trans-unit id="_msg977"> - <source xml:space="preserve">default wallet</source> - <context-group purpose="location"><context context-type="linenumber">601</context></context-group> + <trans-unit id="_msg983"> + <source xml:space="preserve">Can't display address</source> + <context-group purpose="location"><context context-type="linenumber">581</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="_msg978"> + <trans-unit id="_msg984"> <source xml:space="preserve">&Export</source> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg979"> + <trans-unit id="_msg985"> <source xml:space="preserve">Export the data in the current tab to a file</source> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg980"> + <trans-unit id="_msg986"> <source xml:space="preserve">Backup Wallet</source> <context-group purpose="location"><context context-type="linenumber">214</context></context-group> </trans-unit> - <trans-unit id="_msg981"> + <trans-unit id="_msg987"> <source xml:space="preserve">Wallet Data</source> <context-group purpose="location"><context context-type="linenumber">216</context></context-group> <note annotates="source" from="developer">Name of the wallet data file format.</note> </trans-unit> - <trans-unit id="_msg982"> + <trans-unit id="_msg988"> <source xml:space="preserve">Backup Failed</source> <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg983"> + <trans-unit id="_msg989"> <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> </trans-unit> - <trans-unit id="_msg984"> + <trans-unit id="_msg990"> <source xml:space="preserve">Backup Successful</source> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg985"> + <trans-unit id="_msg991"> <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> </trans-unit> - <trans-unit id="_msg986"> + <trans-unit id="_msg992"> <source xml:space="preserve">Cancel</source> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> @@ -4536,902 +4560,1011 @@ Go to File > Open Wallet to load a wallet. </body></file> <file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en"><body> <group restype="x-trolltech-linguist-context" resname="bitcoin-core"> - <trans-unit id="_msg987"> + <trans-unit id="_msg993"> <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="_msg988"> + <trans-unit id="_msg994"> <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="_msg989"> + <trans-unit id="_msg995"> <source xml:space="preserve">%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> <context-group purpose="location"><context context-type="linenumber">16</context></context-group> </trans-unit> - <trans-unit id="_msg990"> + <trans-unit id="_msg996"> <source xml:space="preserve">%s request to listen on port %u. This port is considered "bad" 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">28</context></context-group> </trans-unit> - <trans-unit id="_msg991"> + <trans-unit id="_msg997"> <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">32</context></context-group> </trans-unit> - <trans-unit id="_msg992"> + <trans-unit id="_msg998"> <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">35</context></context-group> </trans-unit> - <trans-unit id="_msg993"> + <trans-unit id="_msg999"> <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">40</context></context-group> </trans-unit> - <trans-unit id="_msg994"> + <trans-unit id="_msg1000"> <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">44</context></context-group> </trans-unit> - <trans-unit id="_msg995"> + <trans-unit id="_msg1001"> <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">47</context></context-group> </trans-unit> - <trans-unit id="_msg996"> + <trans-unit id="_msg1002"> <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">53</context></context-group> </trans-unit> - <trans-unit id="_msg997"> + <trans-unit id="_msg1003"> <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">61</context></context-group> </trans-unit> - <trans-unit id="_msg998"> + <trans-unit id="_msg1004"> <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> <context-group purpose="location"><context context-type="linenumber">67</context></context-group> </trans-unit> - <trans-unit id="_msg999"> + <trans-unit id="_msg1005"> <source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> - <trans-unit id="_msg1000"> + <trans-unit id="_msg1006"> <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">71</context></context-group> </trans-unit> - <trans-unit id="_msg1001"> + <trans-unit id="_msg1007"> <source xml:space="preserve">Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg1002"> + <trans-unit id="_msg1008"> <source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg1003"> + <trans-unit id="_msg1009"> <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">95</context></context-group> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg1004"> + <trans-unit id="_msg1010"> <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">104</context></context-group> + <context-group purpose="location"><context context-type="linenumber">112</context></context-group> </trans-unit> - <trans-unit id="_msg1005"> + <trans-unit id="_msg1011"> <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">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg1006"> + <trans-unit id="_msg1012"> <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + <context-group purpose="location"><context context-type="linenumber">123</context></context-group> </trans-unit> - <trans-unit id="_msg1007"> + <trans-unit id="_msg1013"> <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + <context-group purpose="location"><context context-type="linenumber">126</context></context-group> </trans-unit> - <trans-unit id="_msg1008"> + <trans-unit id="_msg1014"> <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">116</context></context-group> - </trans-unit> - <trans-unit id="_msg1009"> - <source xml:space="preserve">Please check that your computer'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">132</context></context-group> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> </trans-unit> - <trans-unit id="_msg1010"> + <trans-unit id="_msg1015"> <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">135</context></context-group> + <context-group purpose="location"><context context-type="linenumber">144</context></context-group> </trans-unit> - <trans-unit id="_msg1011"> + <trans-unit id="_msg1016"> <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">138</context></context-group> + <context-group purpose="location"><context context-type="linenumber">147</context></context-group> </trans-unit> - <trans-unit id="_msg1012"> + <trans-unit id="_msg1017"> <source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> - <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg1013"> + <trans-unit id="_msg1018"> <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">143</context></context-group> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg1014"> + <trans-unit id="_msg1019"> <source xml:space="preserve">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.</source> - <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> - <trans-unit id="_msg1015"> + <trans-unit id="_msg1020"> <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">150</context></context-group> + <context-group purpose="location"><context context-type="linenumber">162</context></context-group> </trans-unit> - <trans-unit id="_msg1016"> + <trans-unit id="_msg1021"> <source xml:space="preserve">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> - <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> </trans-unit> - <trans-unit id="_msg1017"> + <trans-unit id="_msg1022"> <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">165</context></context-group> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> </trans-unit> - <trans-unit id="_msg1018"> + <trans-unit id="_msg1023"> <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">167</context></context-group> + <context-group purpose="location"><context context-type="linenumber">183</context></context-group> </trans-unit> - <trans-unit id="_msg1019"> + <trans-unit id="_msg1024"> <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">171</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg1020"> + <trans-unit id="_msg1025"> <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">174</context></context-group> + <context-group purpose="location"><context context-type="linenumber">190</context></context-group> </trans-unit> - <trans-unit id="_msg1021"> + <trans-unit id="_msg1026"> <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">177</context></context-group> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> </trans-unit> - <trans-unit id="_msg1022"> + <trans-unit id="_msg1027"> <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">180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg1023"> + <trans-unit id="_msg1028"> <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">182</context></context-group> + <context-group purpose="location"><context context-type="linenumber">198</context></context-group> </trans-unit> - <trans-unit id="_msg1024"> + <trans-unit id="_msg1029"> <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">191</context></context-group> + <context-group purpose="location"><context context-type="linenumber">207</context></context-group> </trans-unit> - <trans-unit id="_msg1025"> + <trans-unit id="_msg1030"> <source xml:space="preserve">Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</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> </trans-unit> - <trans-unit id="_msg1026"> + <trans-unit id="_msg1031"> <source xml:space="preserve">Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <context-group purpose="location"><context context-type="linenumber">209</context></context-group> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg1027"> + <trans-unit id="_msg1032"> <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">212</context></context-group> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> - <trans-unit id="_msg1028"> + <trans-unit id="_msg1033"> <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">215</context></context-group> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg1029"> + <trans-unit id="_msg1034"> <source xml:space="preserve">Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> - <context-group purpose="location"><context context-type="linenumber">219</context></context-group> + <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> - <trans-unit id="_msg1030"> + <trans-unit id="_msg1035"> <source xml:space="preserve">Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg1031"> + <trans-unit id="_msg1036"> <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <context-group purpose="location"><context context-type="linenumber">227</context></context-group> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> - <trans-unit id="_msg1032"> + <trans-unit id="_msg1037"> <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">229</context></context-group> + <context-group purpose="location"><context context-type="linenumber">245</context></context-group> </trans-unit> - <trans-unit id="_msg1033"> + <trans-unit id="_msg1038"> <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">232</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg1034"> + <trans-unit id="_msg1039"> <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">235</context></context-group> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> </trans-unit> - <trans-unit id="_msg1035"> + <trans-unit id="_msg1040"> <source xml:space="preserve">%s is set very high!</source> - <context-group purpose="location"><context context-type="linenumber">244</context></context-group> + <context-group purpose="location"><context context-type="linenumber">270</context></context-group> </trans-unit> - <trans-unit id="_msg1036"> + <trans-unit id="_msg1041"> <source xml:space="preserve">-maxmempool must be at least %d MB</source> - <context-group purpose="location"><context context-type="linenumber">245</context></context-group> - </trans-unit> - <trans-unit id="_msg1037"> - <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source> - <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + <context-group purpose="location"><context context-type="linenumber">271</context></context-group> </trans-unit> - <trans-unit id="_msg1038"> + <trans-unit id="_msg1042"> <source xml:space="preserve">Cannot resolve -%s address: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> - <trans-unit id="_msg1039"> + <trans-unit id="_msg1043"> <source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source> - <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> </trans-unit> - <trans-unit id="_msg1040"> + <trans-unit id="_msg1044"> <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source> - <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> </trans-unit> - <trans-unit id="_msg1041"> + <trans-unit id="_msg1045"> <source xml:space="preserve">Cannot write to data directory '%s'; check permissions.</source> - <context-group purpose="location"><context context-type="linenumber">251</context></context-group> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> </trans-unit> - <trans-unit id="_msg1042"> + <trans-unit id="_msg1046"> <source xml:space="preserve">%s is set very high! Fees this large could be paid on a single transaction.</source> <context-group purpose="location"><context context-type="linenumber">26</context></context-group> </trans-unit> - <trans-unit id="_msg1043"> + <trans-unit id="_msg1047"> <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">37</context></context-group> </trans-unit> - <trans-unit id="_msg1044"> + <trans-unit id="_msg1048"> <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">50</context></context-group> </trans-unit> - <trans-unit id="_msg1045"> + <trans-unit id="_msg1049"> <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg1046"> + <trans-unit id="_msg1050"> <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">64</context></context-group> </trans-unit> - <trans-unit id="_msg1047"> + <trans-unit id="_msg1051"> <source xml:space="preserve">Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg1048"> + <trans-unit id="_msg1052"> <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">80</context></context-group> </trans-unit> - <trans-unit id="_msg1049"> + <trans-unit id="_msg1053"> <source xml:space="preserve">Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg1050"> - <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> + <trans-unit id="_msg1054"> + <source xml:space="preserve">Failed to remove snapshot chainstate dir (%s). Manually remove it before restarting. +</source> <context-group purpose="location"><context context-type="linenumber">89</context></context-group> </trans-unit> - <trans-unit id="_msg1051"> - <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <trans-unit id="_msg1055"> + <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">92</context></context-group> </trans-unit> - <trans-unit id="_msg1052"> + <trans-unit id="_msg1056"> + <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + </trans-unit> + <trans-unit id="_msg1057"> + <source xml:space="preserve">Flushing block file to disk failed. This is likely the result of an I/O error.</source> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + </trans-unit> + <trans-unit id="_msg1058"> + <source xml:space="preserve">Flushing undo file to disk failed. This is likely the result of an I/O error.</source> + <context-group purpose="location"><context context-type="linenumber">104</context></context-group> + </trans-unit> + <trans-unit id="_msg1059"> <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">98</context></context-group> + <context-group purpose="location"><context context-type="linenumber">106</context></context-group> </trans-unit> - <trans-unit id="_msg1053"> + <trans-unit id="_msg1060"> <source xml:space="preserve">Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> - <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + <context-group purpose="location"><context context-type="linenumber">109</context></context-group> </trans-unit> - <trans-unit id="_msg1054"> + <trans-unit id="_msg1061"> + <source xml:space="preserve">Maximum transaction weight is less than transaction weight without inputs</source> + <context-group purpose="location"><context context-type="linenumber">116</context></context-group> + </trans-unit> + <trans-unit id="_msg1062"> + <source xml:space="preserve">Maximum transaction weight is too low, can not accommodate change output</source> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + </trans-unit> + <trans-unit id="_msg1063"> <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> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg1055"> + <trans-unit id="_msg1064"> <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">122</context></context-group> + <context-group purpose="location"><context context-type="linenumber">134</context></context-group> </trans-unit> - <trans-unit id="_msg1056"> + <trans-unit id="_msg1065"> <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">125</context></context-group> + <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg1057"> + <trans-unit id="_msg1066"> <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> + <context-group purpose="location"><context context-type="linenumber">141</context></context-group> </trans-unit> - <trans-unit id="_msg1058"> + <trans-unit id="_msg1067"> + <source xml:space="preserve">Rename of '%s' -> '%s' failed. Cannot clean up the background chainstate leveldb directory.</source> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + </trans-unit> + <trans-unit id="_msg1068"> + <source xml:space="preserve">The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + </trans-unit> + <trans-unit id="_msg1069"> <source xml:space="preserve">The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> - <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg1059"> + <trans-unit id="_msg1070"> <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">161</context></context-group> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg1060"> + <trans-unit id="_msg1071"> <source xml:space="preserve">Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> - <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> </trans-unit> - <trans-unit id="_msg1061"> + <trans-unit id="_msg1072"> <source xml:space="preserve">UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> - <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + <context-group purpose="location"><context context-type="linenumber">204</context></context-group> </trans-unit> - <trans-unit id="_msg1062"> + <trans-unit id="_msg1073"> <source xml:space="preserve">Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> - <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> </trans-unit> - <trans-unit id="_msg1063"> + <trans-unit id="_msg1074"> <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">197</context></context-group> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> - <trans-unit id="_msg1064"> + <trans-unit id="_msg1075"> <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">204</context></context-group> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> - <trans-unit id="_msg1065"> + <trans-unit id="_msg1076"> + <source xml:space="preserve">Your computer's date and time appear to be more than %d minutes out of sync with the network, this may lead to consensus failure. After you've confirmed your computer's clock, this message should no longer appear when you restart your node. Without a restart, it should stop showing automatically after you've connected to a sufficient number of new outbound peers, which may take some time. You can inspect the `timeoffset` field of the `getpeerinfo` and `getnetworkinfo` RPC methods to get more info.</source> + <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + </trans-unit> + <trans-unit id="_msg1077"> <source xml:space="preserve"> Unable to cleanup failed migration</source> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <context-group purpose="location"><context context-type="linenumber">262</context></context-group> </trans-unit> - <trans-unit id="_msg1066"> + <trans-unit id="_msg1078"> <source xml:space="preserve"> Unable to restore backup of wallet.</source> - <context-group purpose="location"><context context-type="linenumber">241</context></context-group> + <context-group purpose="location"><context context-type="linenumber">265</context></context-group> </trans-unit> - <trans-unit id="_msg1067"> + <trans-unit id="_msg1079"> + <source xml:space="preserve">whitebind may only be used for incoming connections ("out" was passed)</source> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + </trans-unit> + <trans-unit id="_msg1080"> + <source xml:space="preserve">A fatal internal error occurred, see debug.log for details: </source> + <context-group purpose="location"><context context-type="linenumber">272</context></context-group> + </trans-unit> + <trans-unit id="_msg1081"> + <source xml:space="preserve">Assumeutxo data not found for the given blockhash '%s'.</source> + <context-group purpose="location"><context context-type="linenumber">273</context></context-group> + </trans-unit> + <trans-unit id="_msg1082"> <source xml:space="preserve">Block verification was interrupted</source> - <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> - <trans-unit id="_msg1068"> + <trans-unit id="_msg1083"> <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">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg1069"> + <trans-unit id="_msg1084"> <source xml:space="preserve">Copyright (C) %i-%i</source> - <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> </trans-unit> - <trans-unit id="_msg1070"> + <trans-unit id="_msg1085"> + <source xml:space="preserve">Corrupt block found indicating potential hardware failure.</source> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + </trans-unit> + <trans-unit id="_msg1086"> <source xml:space="preserve">Corrupted block database detected</source> - <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> </trans-unit> - <trans-unit id="_msg1071"> + <trans-unit id="_msg1087"> <source xml:space="preserve">Could not find asmap file %s</source> - <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> - <trans-unit id="_msg1072"> + <trans-unit id="_msg1088"> <source xml:space="preserve">Could not parse asmap file %s</source> - <context-group purpose="location"><context context-type="linenumber">256</context></context-group> + <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> - <trans-unit id="_msg1073"> + <trans-unit id="_msg1089"> <source xml:space="preserve">Disk space is too low!</source> - <context-group purpose="location"><context context-type="linenumber">257</context></context-group> + <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> - <trans-unit id="_msg1074"> + <trans-unit id="_msg1090"> <source xml:space="preserve">Do you want to rebuild the block database now?</source> - <context-group purpose="location"><context context-type="linenumber">258</context></context-group> + <context-group purpose="location"><context context-type="linenumber">286</context></context-group> </trans-unit> - <trans-unit id="_msg1075"> + <trans-unit id="_msg1091"> <source xml:space="preserve">Done loading</source> - <context-group purpose="location"><context context-type="linenumber">259</context></context-group> + <context-group purpose="location"><context context-type="linenumber">287</context></context-group> </trans-unit> - <trans-unit id="_msg1076"> + <trans-unit id="_msg1092"> <source xml:space="preserve">Dump file %s does not exist.</source> - <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + <context-group purpose="location"><context context-type="linenumber">288</context></context-group> </trans-unit> - <trans-unit id="_msg1077"> + <trans-unit id="_msg1093"> + <source xml:space="preserve">Elliptic curve cryptography sanity check failure. %s is shutting down.</source> + <context-group purpose="location"><context context-type="linenumber">289</context></context-group> + </trans-unit> + <trans-unit id="_msg1094"> <source xml:space="preserve">Error committing db txn for wallet transactions removal</source> - <context-group purpose="location"><context context-type="linenumber">261</context></context-group> + <context-group purpose="location"><context context-type="linenumber">290</context></context-group> </trans-unit> - <trans-unit id="_msg1078"> + <trans-unit id="_msg1095"> <source xml:space="preserve">Error creating %s</source> - <context-group purpose="location"><context context-type="linenumber">262</context></context-group> + <context-group purpose="location"><context context-type="linenumber">291</context></context-group> </trans-unit> - <trans-unit id="_msg1079"> + <trans-unit id="_msg1096"> <source xml:space="preserve">Error initializing block database</source> - <context-group purpose="location"><context context-type="linenumber">263</context></context-group> + <context-group purpose="location"><context context-type="linenumber">292</context></context-group> </trans-unit> - <trans-unit id="_msg1080"> + <trans-unit id="_msg1097"> <source xml:space="preserve">Error initializing wallet database environment %s!</source> - <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> - <trans-unit id="_msg1081"> + <trans-unit id="_msg1098"> <source xml:space="preserve">Error loading %s</source> - <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> - <trans-unit id="_msg1082"> + <trans-unit id="_msg1099"> <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> - <context-group purpose="location"><context context-type="linenumber">266</context></context-group> + <context-group purpose="location"><context context-type="linenumber">295</context></context-group> </trans-unit> - <trans-unit id="_msg1083"> + <trans-unit id="_msg1100"> <source xml:space="preserve">Error loading %s: Wallet corrupted</source> - <context-group purpose="location"><context context-type="linenumber">267</context></context-group> + <context-group purpose="location"><context context-type="linenumber">296</context></context-group> </trans-unit> - <trans-unit id="_msg1084"> + <trans-unit id="_msg1101"> <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> - <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + <context-group purpose="location"><context context-type="linenumber">297</context></context-group> </trans-unit> - <trans-unit id="_msg1085"> + <trans-unit id="_msg1102"> <source xml:space="preserve">Error loading block database</source> - <context-group purpose="location"><context context-type="linenumber">269</context></context-group> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> - <trans-unit id="_msg1086"> + <trans-unit id="_msg1103"> <source xml:space="preserve">Error opening block database</source> - <context-group purpose="location"><context context-type="linenumber">270</context></context-group> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> </trans-unit> - <trans-unit id="_msg1087"> + <trans-unit id="_msg1104"> <source xml:space="preserve">Error reading configuration file: %s</source> - <context-group purpose="location"><context context-type="linenumber">271</context></context-group> + <context-group purpose="location"><context context-type="linenumber">300</context></context-group> </trans-unit> - <trans-unit id="_msg1088"> + <trans-unit id="_msg1105"> <source xml:space="preserve">Error reading from database, shutting down.</source> - <context-group purpose="location"><context context-type="linenumber">272</context></context-group> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg1089"> + <trans-unit id="_msg1106"> <source xml:space="preserve">Error reading next record from wallet database</source> - <context-group purpose="location"><context context-type="linenumber">273</context></context-group> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> - <trans-unit id="_msg1090"> + <trans-unit id="_msg1107"> <source xml:space="preserve">Error starting db txn for wallet transactions removal</source> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg1091"> + <trans-unit id="_msg1108"> <source xml:space="preserve">Error: Cannot extract destination from the generated scriptpubkey</source> - <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg1092"> + <trans-unit id="_msg1109"> <source xml:space="preserve">Error: Couldn't create cursor into database</source> - <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + <context-group purpose="location"><context context-type="linenumber">307</context></context-group> </trans-unit> - <trans-unit id="_msg1093"> + <trans-unit id="_msg1110"> <source xml:space="preserve">Error: Disk space is low for %s</source> - <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + <context-group purpose="location"><context context-type="linenumber">308</context></context-group> </trans-unit> - <trans-unit id="_msg1094"> + <trans-unit id="_msg1111"> <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> - <context-group purpose="location"><context context-type="linenumber">280</context></context-group> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> - <trans-unit id="_msg1095"> + <trans-unit id="_msg1112"> <source xml:space="preserve">Error: Failed to create new watchonly wallet</source> - <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> - <trans-unit id="_msg1096"> + <trans-unit id="_msg1113"> <source xml:space="preserve">Error: Got key that was not hex: %s</source> - <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> - <trans-unit id="_msg1097"> + <trans-unit id="_msg1114"> <source xml:space="preserve">Error: Got value that was not hex: %s</source> - <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> </trans-unit> - <trans-unit id="_msg1098"> + <trans-unit id="_msg1115"> <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> - <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + <context-group purpose="location"><context context-type="linenumber">313</context></context-group> </trans-unit> - <trans-unit id="_msg1099"> + <trans-unit id="_msg1116"> <source xml:space="preserve">Error: Missing checksum</source> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> - <trans-unit id="_msg1100"> + <trans-unit id="_msg1117"> <source xml:space="preserve">Error: No %s addresses available.</source> - <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> </trans-unit> - <trans-unit id="_msg1101"> + <trans-unit id="_msg1118"> <source xml:space="preserve">Error: This wallet already uses SQLite</source> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">316</context></context-group> </trans-unit> - <trans-unit id="_msg1102"> + <trans-unit id="_msg1119"> <source xml:space="preserve">Error: This wallet is already a descriptor wallet</source> - <context-group purpose="location"><context context-type="linenumber">288</context></context-group> + <context-group purpose="location"><context context-type="linenumber">317</context></context-group> </trans-unit> - <trans-unit id="_msg1103"> + <trans-unit id="_msg1120"> <source xml:space="preserve">Error: Unable to begin reading all records in the database</source> - <context-group purpose="location"><context context-type="linenumber">289</context></context-group> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg1104"> + <trans-unit id="_msg1121"> <source xml:space="preserve">Error: Unable to make a backup of your wallet</source> - <context-group purpose="location"><context context-type="linenumber">290</context></context-group> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg1105"> + <trans-unit id="_msg1122"> <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> - <context-group purpose="location"><context context-type="linenumber">291</context></context-group> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> </trans-unit> - <trans-unit id="_msg1106"> + <trans-unit id="_msg1123"> <source xml:space="preserve">Error: Unable to read all records in the database</source> - <context-group purpose="location"><context context-type="linenumber">292</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg1107"> + <trans-unit id="_msg1124"> <source xml:space="preserve">Error: Unable to read wallet's best block locator record</source> - <context-group purpose="location"><context context-type="linenumber">293</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg1108"> + <trans-unit id="_msg1125"> <source xml:space="preserve">Error: Unable to remove watchonly address book data</source> - <context-group purpose="location"><context context-type="linenumber">294</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg1109"> + <trans-unit id="_msg1126"> <source xml:space="preserve">Error: Unable to write record to new wallet</source> - <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg1110"> + <trans-unit id="_msg1127"> <source xml:space="preserve">Error: Unable to write solvable wallet best block locator record</source> - <context-group purpose="location"><context context-type="linenumber">296</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg1111"> + <trans-unit id="_msg1128"> <source xml:space="preserve">Error: Unable to write watchonly wallet best block locator record</source> - <context-group purpose="location"><context context-type="linenumber">297</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg1112"> + <trans-unit id="_msg1129"> <source xml:space="preserve">Error: address book copy failed for wallet %s</source> - <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> </trans-unit> - <trans-unit id="_msg1113"> + <trans-unit id="_msg1130"> <source xml:space="preserve">Error: database transaction cannot be executed for wallet %s</source> - <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <context-group purpose="location"><context context-type="linenumber">328</context></context-group> </trans-unit> - <trans-unit id="_msg1114"> + <trans-unit id="_msg1131"> + <source xml:space="preserve">Failed to connect best block (%s).</source> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + </trans-unit> + <trans-unit id="_msg1132"> + <source xml:space="preserve">Failed to disconnect block.</source> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + </trans-unit> + <trans-unit id="_msg1133"> <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">300</context></context-group> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> </trans-unit> - <trans-unit id="_msg1115"> + <trans-unit id="_msg1134"> + <source xml:space="preserve">Failed to read block.</source> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + </trans-unit> + <trans-unit id="_msg1135"> <source xml:space="preserve">Failed to rescan the wallet during initialization</source> - <context-group purpose="location"><context context-type="linenumber">301</context></context-group> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> </trans-unit> - <trans-unit id="_msg1116"> + <trans-unit id="_msg1136"> <source xml:space="preserve">Failed to start indexes, shutting down..</source> - <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg1117"> + <trans-unit id="_msg1137"> <source xml:space="preserve">Failed to verify database</source> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg1118"> + <trans-unit id="_msg1138"> + <source xml:space="preserve">Failed to write block.</source> + <context-group purpose="location"><context context-type="linenumber">336</context></context-group> + </trans-unit> + <trans-unit id="_msg1139"> + <source xml:space="preserve">Failed to write to block index database.</source> + <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + </trans-unit> + <trans-unit id="_msg1140"> + <source xml:space="preserve">Failed to write to coin database.</source> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + </trans-unit> + <trans-unit id="_msg1141"> + <source xml:space="preserve">Failed to write undo data.</source> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + </trans-unit> + <trans-unit id="_msg1142"> <source xml:space="preserve">Failure removing transaction: %s</source> - <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + <context-group purpose="location"><context context-type="linenumber">340</context></context-group> </trans-unit> - <trans-unit id="_msg1119"> + <trans-unit id="_msg1143"> <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">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg1120"> + <trans-unit id="_msg1144"> <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> - <context-group purpose="location"><context context-type="linenumber">306</context></context-group> + <context-group purpose="location"><context context-type="linenumber">342</context></context-group> </trans-unit> - <trans-unit id="_msg1121"> + <trans-unit id="_msg1145"> <source xml:space="preserve">Importing…</source> - <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> </trans-unit> - <trans-unit id="_msg1122"> + <trans-unit id="_msg1146"> <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg1123"> + <trans-unit id="_msg1147"> <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> - <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + <context-group purpose="location"><context context-type="linenumber">345</context></context-group> </trans-unit> - <trans-unit id="_msg1124"> + <trans-unit id="_msg1148"> <source xml:space="preserve">Input not found or already spent</source> - <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + <context-group purpose="location"><context context-type="linenumber">346</context></context-group> </trans-unit> - <trans-unit id="_msg1125"> + <trans-unit id="_msg1149"> <source xml:space="preserve">Insufficient dbcache for block verification</source> - <context-group purpose="location"><context context-type="linenumber">311</context></context-group> + <context-group purpose="location"><context context-type="linenumber">347</context></context-group> </trans-unit> - <trans-unit id="_msg1126"> + <trans-unit id="_msg1150"> <source xml:space="preserve">Insufficient funds</source> - <context-group purpose="location"><context context-type="linenumber">312</context></context-group> + <context-group purpose="location"><context context-type="linenumber">348</context></context-group> </trans-unit> - <trans-unit id="_msg1127"> + <trans-unit id="_msg1151"> <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">313</context></context-group> + <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg1128"> + <trans-unit id="_msg1152"> <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + <context-group purpose="location"><context context-type="linenumber">350</context></context-group> </trans-unit> - <trans-unit id="_msg1129"> + <trans-unit id="_msg1153"> <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg1130"> + <trans-unit id="_msg1154"> <source xml:space="preserve">Invalid P2P permission: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">316</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> - <trans-unit id="_msg1131"> + <trans-unit id="_msg1155"> <source xml:space="preserve">Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> - <context-group purpose="location"><context context-type="linenumber">317</context></context-group> + <context-group purpose="location"><context context-type="linenumber">353</context></context-group> </trans-unit> - <trans-unit id="_msg1132"> + <trans-unit id="_msg1156"> <source xml:space="preserve">Invalid amount for %s=<amount>: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> </trans-unit> - <trans-unit id="_msg1133"> + <trans-unit id="_msg1157"> <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">355</context></context-group> </trans-unit> - <trans-unit id="_msg1134"> + <trans-unit id="_msg1158"> <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">320</context></context-group> + <context-group purpose="location"><context context-type="linenumber">356</context></context-group> </trans-unit> - <trans-unit id="_msg1135"> + <trans-unit id="_msg1159"> <source xml:space="preserve">Invalid port specified in %s: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + <context-group purpose="location"><context context-type="linenumber">357</context></context-group> </trans-unit> - <trans-unit id="_msg1136"> + <trans-unit id="_msg1160"> <source xml:space="preserve">Invalid pre-selected input %s</source> - <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + <context-group purpose="location"><context context-type="linenumber">358</context></context-group> </trans-unit> - <trans-unit id="_msg1137"> + <trans-unit id="_msg1161"> <source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source> - <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> </trans-unit> - <trans-unit id="_msg1138"> + <trans-unit id="_msg1162"> <source xml:space="preserve">Loading P2P addresses…</source> - <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + <context-group purpose="location"><context context-type="linenumber">360</context></context-group> </trans-unit> - <trans-unit id="_msg1139"> + <trans-unit id="_msg1163"> <source xml:space="preserve">Loading banlist…</source> - <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> </trans-unit> - <trans-unit id="_msg1140"> + <trans-unit id="_msg1164"> <source xml:space="preserve">Loading block index…</source> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <context-group purpose="location"><context context-type="linenumber">362</context></context-group> </trans-unit> - <trans-unit id="_msg1141"> + <trans-unit id="_msg1165"> <source xml:space="preserve">Loading wallet…</source> - <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + <context-group purpose="location"><context context-type="linenumber">363</context></context-group> </trans-unit> - <trans-unit id="_msg1142"> + <trans-unit id="_msg1166"> + <source xml:space="preserve">Maximum transaction weight must be between %d and %d</source> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> + </trans-unit> + <trans-unit id="_msg1167"> <source xml:space="preserve">Missing amount</source> - <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + <context-group purpose="location"><context context-type="linenumber">365</context></context-group> </trans-unit> - <trans-unit id="_msg1143"> + <trans-unit id="_msg1168"> <source xml:space="preserve">Missing solving data for estimating transaction size</source> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">366</context></context-group> </trans-unit> - <trans-unit id="_msg1144"> + <trans-unit id="_msg1169"> <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <context-group purpose="location"><context context-type="linenumber">367</context></context-group> </trans-unit> - <trans-unit id="_msg1145"> + <trans-unit id="_msg1170"> <source xml:space="preserve">No addresses available</source> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">368</context></context-group> </trans-unit> - <trans-unit id="_msg1146"> + <trans-unit id="_msg1171"> <source xml:space="preserve">Not enough file descriptors available.</source> - <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> </trans-unit> - <trans-unit id="_msg1147"> + <trans-unit id="_msg1172"> <source xml:space="preserve">Not found pre-selected input %s</source> - <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + <context-group purpose="location"><context context-type="linenumber">370</context></context-group> </trans-unit> - <trans-unit id="_msg1148"> + <trans-unit id="_msg1173"> <source xml:space="preserve">Not solvable pre-selected input %s</source> - <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> - <trans-unit id="_msg1149"> + <trans-unit id="_msg1174"> + <source xml:space="preserve">Only direction was set, no permissions: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + </trans-unit> + <trans-unit id="_msg1175"> <source xml:space="preserve">Prune cannot be configured with a negative value.</source> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> - <trans-unit id="_msg1150"> + <trans-unit id="_msg1176"> <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> - <context-group purpose="location"><context context-type="linenumber">336</context></context-group> + <context-group purpose="location"><context context-type="linenumber">374</context></context-group> </trans-unit> - <trans-unit id="_msg1151"> + <trans-unit id="_msg1177"> <source xml:space="preserve">Pruning blockstore…</source> - <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg1152"> + <trans-unit id="_msg1178"> <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> - <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + <context-group purpose="location"><context context-type="linenumber">376</context></context-group> </trans-unit> - <trans-unit id="_msg1153"> + <trans-unit id="_msg1179"> <source xml:space="preserve">Replaying blocks…</source> - <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + <context-group purpose="location"><context context-type="linenumber">377</context></context-group> </trans-unit> - <trans-unit id="_msg1154"> + <trans-unit id="_msg1180"> <source xml:space="preserve">Rescanning…</source> - <context-group purpose="location"><context context-type="linenumber">340</context></context-group> + <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> - <trans-unit id="_msg1155"> + <trans-unit id="_msg1181"> <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> </trans-unit> - <trans-unit id="_msg1156"> + <trans-unit id="_msg1182"> <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> - <context-group purpose="location"><context context-type="linenumber">342</context></context-group> + <context-group purpose="location"><context context-type="linenumber">380</context></context-group> </trans-unit> - <trans-unit id="_msg1157"> + <trans-unit id="_msg1183"> <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> - <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">381</context></context-group> </trans-unit> - <trans-unit id="_msg1158"> + <trans-unit id="_msg1184"> <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> - <context-group purpose="location"><context context-type="linenumber">344</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> - <trans-unit id="_msg1159"> + <trans-unit id="_msg1185"> <source xml:space="preserve">Section [%s] is not recognized.</source> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">383</context></context-group> </trans-unit> - <trans-unit id="_msg1160"> + <trans-unit id="_msg1186"> + <source xml:space="preserve">Signer did not echo address</source> + <context-group purpose="location"><context context-type="linenumber">386</context></context-group> + </trans-unit> + <trans-unit id="_msg1187"> + <source xml:space="preserve">Signer echoed unexpected address %s</source> + <context-group purpose="location"><context context-type="linenumber">387</context></context-group> + </trans-unit> + <trans-unit id="_msg1188"> + <source xml:space="preserve">Signer returned error: %s</source> + <context-group purpose="location"><context context-type="linenumber">388</context></context-group> + </trans-unit> + <trans-unit id="_msg1189"> <source xml:space="preserve">Signing transaction failed</source> - <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + <context-group purpose="location"><context context-type="linenumber">389</context></context-group> </trans-unit> - <trans-unit id="_msg1161"> + <trans-unit id="_msg1190"> <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> - <context-group purpose="location"><context context-type="linenumber">349</context></context-group> + <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg1162"> + <trans-unit id="_msg1191"> <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> - <context-group purpose="location"><context context-type="linenumber">350</context></context-group> + <context-group purpose="location"><context context-type="linenumber">391</context></context-group> </trans-unit> - <trans-unit id="_msg1163"> + <trans-unit id="_msg1192"> <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> - <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> - <trans-unit id="_msg1164"> + <trans-unit id="_msg1193"> <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + <context-group purpose="location"><context context-type="linenumber">393</context></context-group> </trans-unit> - <trans-unit id="_msg1165"> + <trans-unit id="_msg1194"> <source xml:space="preserve">Specified data directory "%s" does not exist.</source> - <context-group purpose="location"><context context-type="linenumber">353</context></context-group> + <context-group purpose="location"><context context-type="linenumber">394</context></context-group> </trans-unit> - <trans-unit id="_msg1166"> + <trans-unit id="_msg1195"> <source xml:space="preserve">Starting network threads…</source> - <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">395</context></context-group> </trans-unit> - <trans-unit id="_msg1167"> + <trans-unit id="_msg1196"> + <source xml:space="preserve">System error while flushing: %s</source> + <context-group purpose="location"><context context-type="linenumber">396</context></context-group> + </trans-unit> + <trans-unit id="_msg1197"> + <source xml:space="preserve">System error while loading external block file: %s</source> + <context-group purpose="location"><context context-type="linenumber">397</context></context-group> + </trans-unit> + <trans-unit id="_msg1198"> + <source xml:space="preserve">System error while saving block to disk: %s</source> + <context-group purpose="location"><context context-type="linenumber">398</context></context-group> + </trans-unit> + <trans-unit id="_msg1199"> <source xml:space="preserve">The source code is available from %s.</source> - <context-group purpose="location"><context context-type="linenumber">355</context></context-group> + <context-group purpose="location"><context context-type="linenumber">399</context></context-group> </trans-unit> - <trans-unit id="_msg1168"> + <trans-unit id="_msg1200"> <source xml:space="preserve">The specified config file %s does not exist</source> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">400</context></context-group> </trans-unit> - <trans-unit id="_msg1169"> + <trans-unit id="_msg1201"> <source xml:space="preserve">The transaction amount is too small to pay the fee</source> - <context-group purpose="location"><context context-type="linenumber">357</context></context-group> + <context-group purpose="location"><context context-type="linenumber">401</context></context-group> </trans-unit> - <trans-unit id="_msg1170"> + <trans-unit id="_msg1202"> <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> - <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + <context-group purpose="location"><context context-type="linenumber">402</context></context-group> </trans-unit> - <trans-unit id="_msg1171"> + <trans-unit id="_msg1203"> + <source xml:space="preserve">There is no ScriptPubKeyManager for this address</source> + <context-group purpose="location"><context context-type="linenumber">403</context></context-group> + </trans-unit> + <trans-unit id="_msg1204"> <source xml:space="preserve">This is experimental software.</source> - <context-group purpose="location"><context context-type="linenumber">359</context></context-group> + <context-group purpose="location"><context context-type="linenumber">404</context></context-group> </trans-unit> - <trans-unit id="_msg1172"> + <trans-unit id="_msg1205"> <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> - <context-group purpose="location"><context context-type="linenumber">360</context></context-group> + <context-group purpose="location"><context context-type="linenumber">405</context></context-group> </trans-unit> - <trans-unit id="_msg1173"> + <trans-unit id="_msg1206"> <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">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">406</context></context-group> </trans-unit> - <trans-unit id="_msg1174"> + <trans-unit id="_msg1207"> <source xml:space="preserve">Transaction %s does not belong to this wallet</source> - <context-group purpose="location"><context context-type="linenumber">362</context></context-group> + <context-group purpose="location"><context context-type="linenumber">407</context></context-group> </trans-unit> - <trans-unit id="_msg1175"> + <trans-unit id="_msg1208"> <source xml:space="preserve">Transaction amount too small</source> - <context-group purpose="location"><context context-type="linenumber">363</context></context-group> + <context-group purpose="location"><context context-type="linenumber">408</context></context-group> </trans-unit> - <trans-unit id="_msg1176"> + <trans-unit id="_msg1209"> <source xml:space="preserve">Transaction amounts must not be negative</source> - <context-group purpose="location"><context context-type="linenumber">364</context></context-group> + <context-group purpose="location"><context context-type="linenumber">409</context></context-group> </trans-unit> - <trans-unit id="_msg1177"> + <trans-unit id="_msg1210"> <source xml:space="preserve">Transaction change output index out of range</source> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">410</context></context-group> </trans-unit> - <trans-unit id="_msg1178"> + <trans-unit id="_msg1211"> <source xml:space="preserve">Transaction must have at least one recipient</source> - <context-group purpose="location"><context context-type="linenumber">366</context></context-group> + <context-group purpose="location"><context context-type="linenumber">411</context></context-group> </trans-unit> - <trans-unit id="_msg1179"> + <trans-unit id="_msg1212"> <source xml:space="preserve">Transaction needs a change address, but we can't generate it.</source> - <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + <context-group purpose="location"><context context-type="linenumber">412</context></context-group> </trans-unit> - <trans-unit id="_msg1180"> + <trans-unit id="_msg1213"> <source xml:space="preserve">Transaction too large</source> - <context-group purpose="location"><context context-type="linenumber">368</context></context-group> + <context-group purpose="location"><context context-type="linenumber">413</context></context-group> </trans-unit> - <trans-unit id="_msg1181"> - <source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <context-group purpose="location"><context context-type="linenumber">369</context></context-group> - </trans-unit> - <trans-unit id="_msg1182"> + <trans-unit id="_msg1214"> <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">370</context></context-group> + <context-group purpose="location"><context context-type="linenumber">414</context></context-group> </trans-unit> - <trans-unit id="_msg1183"> + <trans-unit id="_msg1215"> <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">371</context></context-group> + <context-group purpose="location"><context context-type="linenumber">415</context></context-group> </trans-unit> - <trans-unit id="_msg1184"> + <trans-unit id="_msg1216"> <source xml:space="preserve">Unable to create the PID file '%s': %s</source> - <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + <context-group purpose="location"><context context-type="linenumber">416</context></context-group> </trans-unit> - <trans-unit id="_msg1185"> + <trans-unit id="_msg1217"> <source xml:space="preserve">Unable to find UTXO for external input</source> - <context-group purpose="location"><context context-type="linenumber">373</context></context-group> + <context-group purpose="location"><context context-type="linenumber">417</context></context-group> </trans-unit> - <trans-unit id="_msg1186"> + <trans-unit id="_msg1218"> <source xml:space="preserve">Unable to generate initial keys</source> - <context-group purpose="location"><context context-type="linenumber">374</context></context-group> + <context-group purpose="location"><context context-type="linenumber">418</context></context-group> </trans-unit> - <trans-unit id="_msg1187"> + <trans-unit id="_msg1219"> <source xml:space="preserve">Unable to generate keys</source> - <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + <context-group purpose="location"><context context-type="linenumber">419</context></context-group> </trans-unit> - <trans-unit id="_msg1188"> + <trans-unit id="_msg1220"> <source xml:space="preserve">Unable to open %s for writing</source> - <context-group purpose="location"><context context-type="linenumber">376</context></context-group> + <context-group purpose="location"><context context-type="linenumber">420</context></context-group> </trans-unit> - <trans-unit id="_msg1189"> + <trans-unit id="_msg1221"> <source xml:space="preserve">Unable to parse -maxuploadtarget: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">377</context></context-group> + <context-group purpose="location"><context context-type="linenumber">421</context></context-group> </trans-unit> - <trans-unit id="_msg1190"> + <trans-unit id="_msg1222"> <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> - <context-group purpose="location"><context context-type="linenumber">378</context></context-group> + <context-group purpose="location"><context context-type="linenumber">422</context></context-group> </trans-unit> - <trans-unit id="_msg1191"> + <trans-unit id="_msg1223"> <source xml:space="preserve">Unable to unload the wallet before migrating</source> - <context-group purpose="location"><context context-type="linenumber">379</context></context-group> + <context-group purpose="location"><context context-type="linenumber">423</context></context-group> </trans-unit> - <trans-unit id="_msg1192"> + <trans-unit id="_msg1224"> <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> - <context-group purpose="location"><context context-type="linenumber">380</context></context-group> + <context-group purpose="location"><context context-type="linenumber">424</context></context-group> </trans-unit> - <trans-unit id="_msg1193"> + <trans-unit id="_msg1225"> <source xml:space="preserve">Unknown address type '%s'</source> - <context-group purpose="location"><context context-type="linenumber">381</context></context-group> + <context-group purpose="location"><context context-type="linenumber">425</context></context-group> </trans-unit> - <trans-unit id="_msg1194"> + <trans-unit id="_msg1226"> <source xml:space="preserve">Unknown change type '%s'</source> - <context-group purpose="location"><context context-type="linenumber">382</context></context-group> + <context-group purpose="location"><context context-type="linenumber">426</context></context-group> </trans-unit> - <trans-unit id="_msg1195"> + <trans-unit id="_msg1227"> <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">383</context></context-group> + <context-group purpose="location"><context context-type="linenumber">427</context></context-group> </trans-unit> - <trans-unit id="_msg1196"> + <trans-unit id="_msg1228"> <source xml:space="preserve">Unknown new rules activated (versionbit %i)</source> - <context-group purpose="location"><context context-type="linenumber">384</context></context-group> + <context-group purpose="location"><context context-type="linenumber">428</context></context-group> </trans-unit> - <trans-unit id="_msg1197"> + <trans-unit id="_msg1229"> + <source xml:space="preserve">Unrecognised option "%s" provided in -test=<option>.</source> + <context-group purpose="location"><context context-type="linenumber">429</context></context-group> + </trans-unit> + <trans-unit id="_msg1230"> <source xml:space="preserve">Unsupported global logging level %s=%s. Valid values: %s.</source> - <context-group purpose="location"><context context-type="linenumber">385</context></context-group> + <context-group purpose="location"><context context-type="linenumber">430</context></context-group> </trans-unit> - <trans-unit id="_msg1198"> + <trans-unit id="_msg1231"> <source xml:space="preserve">Wallet file creation failed: %s</source> - <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + <context-group purpose="location"><context context-type="linenumber">435</context></context-group> </trans-unit> - <trans-unit id="_msg1199"> + <trans-unit id="_msg1232"> <source xml:space="preserve">acceptstalefeeestimates is not supported on %s chain.</source> - <context-group purpose="location"><context context-type="linenumber">392</context></context-group> + <context-group purpose="location"><context context-type="linenumber">437</context></context-group> </trans-unit> - <trans-unit id="_msg1200"> + <trans-unit id="_msg1233"> <source xml:space="preserve">Unsupported logging category %s=%s.</source> - <context-group purpose="location"><context context-type="linenumber">386</context></context-group> + <context-group purpose="location"><context context-type="linenumber">431</context></context-group> </trans-unit> - <trans-unit id="_msg1201"> + <trans-unit id="_msg1234"> <source xml:space="preserve">Error: Could not add watchonly tx %s to watchonly wallet</source> - <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg1202"> + <trans-unit id="_msg1235"> <source xml:space="preserve">Error: Could not delete watchonly transactions. </source> - <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg1203"> + <trans-unit id="_msg1236"> <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> - <context-group purpose="location"><context context-type="linenumber">387</context></context-group> + <context-group purpose="location"><context context-type="linenumber">432</context></context-group> </trans-unit> - <trans-unit id="_msg1204"> + <trans-unit id="_msg1237"> <source xml:space="preserve">Verifying blocks…</source> - <context-group purpose="location"><context context-type="linenumber">388</context></context-group> + <context-group purpose="location"><context context-type="linenumber">433</context></context-group> </trans-unit> - <trans-unit id="_msg1205"> + <trans-unit id="_msg1238"> <source xml:space="preserve">Verifying wallet(s)…</source> - <context-group purpose="location"><context context-type="linenumber">389</context></context-group> + <context-group purpose="location"><context context-type="linenumber">434</context></context-group> </trans-unit> - <trans-unit id="_msg1206"> + <trans-unit id="_msg1239"> <source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source> - <context-group purpose="location"><context context-type="linenumber">391</context></context-group> + <context-group purpose="location"><context context-type="linenumber">436</context></context-group> </trans-unit> - <trans-unit id="_msg1207"> + <trans-unit id="_msg1240"> <source xml:space="preserve">Settings file could not be read</source> - <context-group purpose="location"><context context-type="linenumber">346</context></context-group> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> </trans-unit> - <trans-unit id="_msg1208"> + <trans-unit id="_msg1241"> <source xml:space="preserve">Settings file could not be written</source> - <context-group purpose="location"><context context-type="linenumber">347</context></context-group> + <context-group purpose="location"><context context-type="linenumber">385</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 3b44647095..6b8474cf76 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -258,36 +258,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 sekundo</numerusform> + <numerusform>%n sekundoj</numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n minuto</numerusform> + <numerusform>%n minutoj</numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n horo</numerusform> + <numerusform>%n horoj</numerusform> </translation> </message> <message numerus="yes"> <source>%n day(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n tago</numerusform> + <numerusform>%n tagoj</numerusform> </translation> </message> <message numerus="yes"> <source>%n week(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n semajno</numerusform> + <numerusform>%n semajnoj</numerusform> </translation> </message> <message> @@ -297,8 +297,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 jaro</numerusform> + <numerusform>%n jaroj</numerusform> </translation> </message> </context> @@ -834,8 +834,8 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n gigabajto de libera loko disponeble</numerusform> + <numerusform>%n gigabajtoj de libera loko disponebla.</numerusform> </translation> </message> <message numerus="yes"> @@ -2144,6 +2144,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Subskriba transakcio fiaskis</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">la elektita dosierujo por datumoj "%s" ne ekzistas.</translation> + </message> + <message> <source>This is experimental software.</source> <translation type="unfinished">Äi estas eksperimenta programo</translation> </message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index 585df2e497..9f3940b07e 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -520,7 +520,7 @@ Solo es posible firmar con direcciones de tipo "legacy".</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Firmar mensajes con tus direcciones Bitcoin para probar la propiedad</translation> + <translation type="unfinished">Firmar mensajes con tus direcciones de Bitcoin para probar la propiedad</translation> </message> <message> <source>&Verify message…</source> @@ -1252,7 +1252,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (se requiere para la firma externa)</translation> </message> </context> <context> @@ -1562,7 +1562,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </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 (por ejemplo, IPv4: 127.0.0.1 / IPv6: ::1)</translation> + <translation type="unfinished">Dirección IP del proxy (p. ej., 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> @@ -1570,7 +1570,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </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> + <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 solo se cerrará después de seleccionar "Salir" en el menú.</translation> </message> <message> <source>Font in the Overview tab: </source> @@ -1611,7 +1611,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <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 del 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> @@ -1665,12 +1665,12 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <message> <source>Enable &PSBT controls</source> <extracomment>An options window setting to enable PSBT controls.</extracomment> - <translation type="unfinished">Activar controles &TBPF</translation> + <translation type="unfinished">Activar controles de &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 TBPF</translation> + <translation type="unfinished">Establecer si se muestran los controles de TBPF</translation> </message> <message> <source>External Signer (e.g. hardware wallet)</source> @@ -1774,7 +1774,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </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 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> + <translation type="unfinished">URL 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>&Third-party transaction URLs</source> @@ -1803,7 +1803,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <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 (requerido para la firma externa)</translation> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (se requiere para la firma externa)</translation> </message> <message> <source>default</source> @@ -1903,7 +1903,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </message> <message> <source>Immature:</source> - <translation type="unfinished">Inmadura:</translation> + <translation type="unfinished">Inmaduro:</translation> </message> <message> <source>Mined balance that has not yet matured</source> @@ -1950,7 +1950,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi <name>PSBTOperationsDialog</name> <message> <source>PSBT Operations</source> - <translation type="unfinished">Operaciones TBPF</translation> + <translation type="unfinished">Operaciones de TBPF</translation> </message> <message> <source>Sign Tx</source> @@ -2063,7 +2063,7 @@ El proceso de migración creará una copia de seguridad del monedero antes de mi </message> <message> <source>(But no wallet is loaded.)</source> - <translation type="unfinished">(No existe ningún monedero cargado).</translation> + <translation type="unfinished">(No hay ningún monedero cargado).</translation> </message> <message> <source>(But this wallet cannot sign transactions.)</source> @@ -2114,7 +2114,7 @@ Si recibes este error, debes solicitar al comerciante que te proporcione un URI </message> <message> <source>Payment request file handling</source> - <translation type="unfinished">Gestión del archivo de solicitud de pago</translation> + <translation type="unfinished">Gestión de archivos de solicitud de pago</translation> </message> </context> <context> diff --git a/src/qt/locale/bitcoin_es_CO.ts b/src/qt/locale/bitcoin_es_CO.ts index 1451f88104..9ff4e9234f 100644 --- a/src/qt/locale/bitcoin_es_CO.ts +++ b/src/qt/locale/bitcoin_es_CO.ts @@ -299,6 +299,10 @@ Solo es posible firmar con direcciones de tipo legacy.</translation> <translation type="unfinished">desconocido</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">"%1" integrado</translation> + </message> + <message> <source>Default system font "%1"</source> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -704,7 +708,7 @@ Solo es posible firmar con direcciones de tipo legacy.</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> + <translation type="unfinished">Ocultar los valores en la pestaña "Vista general"</translation> </message> <message> <source>default wallet</source> @@ -1087,11 +1091,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Guiones vigilantes han sido migrados a un monedero con el nombre '%1'.</translation> + <translation type="unfinished">Los scripts solo de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Solucionable pero ninguno de los guiones vigilados han sido migrados a un monedero llamados '%1'.</translation> + <translation type="unfinished">Los scripts solucionables pero no de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Migration failed</source> @@ -1565,7 +1569,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Font in the Overview tab: </source> - <translation type="unfinished">Fuente en la pestaña Resumen:</translation> + <translation type="unfinished">Fuente en la pestaña "Vista general":</translation> </message> <message> <source>Options set in this dialog are overridden by the command line:</source> @@ -2646,7 +2650,7 @@ Para obtener más información sobre cómo usar esta consola, escribe %6. </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>From</source> @@ -3121,7 +3125,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 desde monedero "%2"</translation> + <translation type="unfinished">%1 desde billetera "%2"</translation> </message> <message> <source>Do you want to create this transaction?</source> @@ -3194,7 +3198,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Transaction creation failed!</source> - <translation type="unfinished">¡Fallo al crear la transacción!</translation> + <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> @@ -3510,7 +3514,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>own address</source> @@ -4342,7 +4346,7 @@ Ir a "Archivo > Abrir billetera" para cargar una. The wallet might have been tampered with or created with malicious intent. </source> - <translation type="unfinished">Se encontró una entrada heredada inesperada en la billetera basada en descriptores. Cargando billetera%s + <translation type="unfinished">Se encontró una entrada inesperada tipo "legacy" en la billetera basada en descriptores. Cargando billetera%s Es posible que la billetera haya sido manipulada o creada con malas intenciones. </translation> @@ -4533,7 +4537,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Error: no es capaz de leer el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo leer el registro del mejor localizador de bloques de la billetera.</translation> </message> <message> <source>Error: Unable to remove watchonly address book data</source> @@ -4545,16 +4549,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solucionable.</translation> </message> <message> <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor monedero vigilado del bloque del registro localizador</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solo de observación.</translation> </message> <message> <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera 1%s - </translation> + <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera %s</translation> </message> <message> <source>Error: database transaction cannot be executed for wallet %s</source> @@ -4578,7 +4581,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failure removing transaction: %s</source> - <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> + <translation type="unfinished">Error al eliminar la transacción: %s</translation> </message> <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> @@ -4898,7 +4901,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Creación errónea del fichero monedero: %s</translation> + <translation type="unfinished">Error al crear el archivo de la billetera: %s</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> @@ -4910,11 +4913,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Error: no pudo agregar tx de solo vigÃa %s para monedero de solo vigÃa</translation> + <translation type="unfinished">Error: No se pudo agregar la transacción %s a la billetera solo de observación.</translation> </message> <message> <source>Error: Could not delete watchonly transactions. </source> - <translation type="unfinished">Error: no se pudieron eliminar las transacciones de watchonly.</translation> + <translation type="unfinished">Error: No se pudieron eliminar las transacciones solo de observación</translation> </message> <message> <source>User Agent comment (%s) contains unsafe characters.</source> diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index b49fe13730..c8342ad3bc 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Click derecho para editar la dirección o etiqueta</translation> + <translation type="unfinished">Hacer clic derecho para editar la dirección o etiqueta</translation> </message> <message> <source>Create a new address</source> @@ -11,11 +11,11 @@ </message> <message> <source>&New</source> - <translation type="unfinished">&Nuevo</translation> + <translation type="unfinished">&Nueva</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copie las direcciones seleccionadas actualmente al portapapeles del sistema</translation> + <translation type="unfinished">Copiar la dirección seleccionada actualmente al portapapeles del sistema</translation> </message> <message> <source>&Copy</source> @@ -23,19 +23,19 @@ </message> <message> <source>C&lose</source> - <translation type="unfinished">C&errar</translation> + <translation type="unfinished">&Cerrar</translation> </message> <message> <source>Delete the currently selected address from the list</source> - <translation type="unfinished">Borrar las direcciones seleccionadas recientemente de la lista</translation> + <translation type="unfinished">Eliminar la dirección seleccionada de la lista</translation> </message> <message> <source>Enter address or label to search</source> - <translation type="unfinished">Introduzca una dirección o etiqueta que buscar</translation> + <translation type="unfinished">Ingresar una dirección o etiqueta para buscar</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar los datos en la pestaña actual a un archivo</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> <source>&Export</source> @@ -47,32 +47,33 @@ </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished">Escoja la direccion a enviar las monedas</translation> + <translation type="unfinished">Elige la dirección a la que se enviarán monedas</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished">Elige la dirección para recibir monedas</translation> + <translation type="unfinished">Elige la dirección con la que se recibirán monedas</translation> </message> <message> <source>C&hoose</source> - <translation type="unfinished">Escoger</translation> + <translation type="unfinished">&Seleccionar</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">Estas son tus direcciones Bitcoin para realizar pagos. Verifica siempre el monto y la dirección de recepción antes de enviar monedas. </translation> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para enviar pagos. Revisa siempre el importe 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> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para recibir pagos. Usa el botón "Crear nueva dirección de recepción" en la pestaña "Recibir" para crear nuevas direcciones. +Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>&Copy Address</source> - <translation type="unfinished">Copiar dirección</translation> + <translation type="unfinished">&Copiar dirección</translation> </message> <message> <source>Copy &Label</source> - <translation type="unfinished">Copiar &Etiqueta</translation> + <translation type="unfinished">Copiar &etiqueta</translation> </message> <message> <source>&Edit</source> @@ -90,12 +91,15 @@ 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">Tuvimos un problema al guardar la dirección en la lista %1. Intenta de Nuevo.</translation> + <translation type="unfinished">Ocurrió un error al intentar guardar la lista de direcciones en %1. Inténtalo de nuevo.</translation> + </message> + <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">Direcciones de envÃo - %1</translation> </message> <message> <source>Receiving addresses - %1</source> - <translation type="unfinished">Recepción de direcciones - %1 -</translation> + <translation type="unfinished">Direcciones de recepción - %1</translation> </message> <message> <source>Exporting Failed</source> @@ -106,11 +110,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <name>AddressTableModel</name> <message> <source>Label</source> - <translation type="unfinished">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> </message> <message> <source>Address</source> - <translation type="unfinished">Direccion</translation> + <translation type="unfinished">Dirección</translation> </message> <message> <source>(no label)</source> @@ -121,11 +125,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation type="unfinished">Diálogo contraseña</translation> + <translation type="unfinished">Diálogo de frase de contraseña</translation> </message> <message> <source>Enter passphrase</source> - <translation type="unfinished">Ingresa frase de contraseña</translation> + <translation type="unfinished">Ingresar la frase de contraseña</translation> </message> <message> <source>New passphrase</source> @@ -133,92 +137,91 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Repetir nueva frase de contraseña</translation> + <translation type="unfinished">Repetir la nueva frase de contraseña</translation> </message> <message> <source>Show passphrase</source> - <translation type="unfinished">Mostrar frase de contraseña</translation> + <translation type="unfinished">Mostrar la frase de contraseña</translation> </message> <message> <source>Encrypt wallet</source> - <translation type="unfinished">Cifrar monedero</translation> + <translation type="unfinished">Encriptar billetera</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Esta operación necesita su frase de contraseña de la billetera para desbloquearla. -</translation> + <translation type="unfinished">Esta operación requiere la frase de contraseña de la billetera para desbloquearla.</translation> </message> <message> <source>Unlock wallet</source> - <translation type="unfinished">Desbloquear monedero</translation> + <translation type="unfinished">Desbloquear billetera</translation> </message> <message> <source>Change passphrase</source> - <translation type="unfinished">Cambiar frase secreta</translation> + <translation type="unfinished">Cambiar frase de contraseña</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation type="unfinished">Confirmar cifrado de billetera</translation> + <translation type="unfinished">Confirmar el encriptado de la billetera</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation type="unfinished">Atención: Si cifra su monedero y pierde la contraseña, perderá ¡<b>TODOS SUS BITCOINS</b>!</translation> + <translation type="unfinished">Advertencia: Si encriptas la billetera y pierdes tu frase de contraseña, ¡<b>PERDERÃS TODOS TUS BITCOINS</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">¿Está seguro que desea cifrar su monedero?</translation> + <translation type="unfinished">¿Seguro quieres encriptar la billetera?</translation> </message> <message> <source>Wallet encrypted</source> - <translation type="unfinished">Monedero cifrado</translation> + <translation type="unfinished">Billetera encriptada</translation> </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation type="unfinished">Ingrese la nueva frase de contraseña para la billetera<br/>. Utilice una frase de cont<b>raseñade diez o más caracteres</b> aleatorios o och<b>o o más palab</b>ras.</translation> + <translation type="unfinished">Ingresa la nueva frase de contraseña para la billetera. <br/>Usa una frase de contraseña de <b>diez o más caracteres aleatorios</b>, u <b>ocho o más palabras</b>.</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> + <translation type="unfinished">Ingresa la antigua frase de contraseña 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> + <translation type="unfinished">Recuerda que encriptar tu billetera no garantiza la protección total contra el robo de tus bitcoins si la computadora está infectada con malware.</translation> </message> <message> <source>Wallet to be encrypted</source> - <translation type="unfinished">Billetera para ser cifrada</translation> + <translation type="unfinished">Billetera para encriptar</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> - <translation type="unfinished">Tu monedero va a ser cifrado</translation> + <translation type="unfinished">Tu billetera está a punto de encriptarse.</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Tu monedero está ahora cifrado</translation> + <translation type="unfinished">Tu billetera ahora está encriptada.</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> + <translation type="unfinished">IMPORTANTE: Cualquier copia de seguridad anterior que hayas hecho del archivo de la billetera se deberá reemplazar por el nuevo archivo encriptado que generaste. Por motivos de seguridad, las copias de seguridad realizadas anteriormente quedarán obsoletas en cuanto empieces a usar la nueva billetera encriptada.</translation> </message> <message> <source>Wallet encryption failed</source> - <translation type="unfinished">Ha fallado el cifrado del monedero</translation> + <translation type="unfinished">Falló el encriptado de la billetera</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">Ha fallado el cifrado del monedero debido a un error interno. El monedero no ha sido cifrado.</translation> + <translation type="unfinished">El encriptado de la billetera falló debido a un error interno. La billetera no se encriptó.</translation> </message> <message> <source>The supplied passphrases do not match.</source> - <translation type="unfinished">Las contraseñas no coinciden.</translation> + <translation type="unfinished">Las frases de contraseña proporcionadas no coinciden.</translation> </message> <message> <source>Wallet unlock failed</source> - <translation type="unfinished">Ha fallado el desbloqueo del monedero</translation> + <translation type="unfinished">Falló el desbloqueo de la billetera</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">La contraseña introducida para descifrar el monedero es incorrecta.</translation> + <translation type="unfinished">La frase de contraseña introducida para el cifrado de la billetera es incorrecta.</translation> </message> <message> <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> @@ -226,7 +229,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">Se ha cambiado correctamente la contraseña del monedero.</translation> + <translation type="unfinished">La frase de contraseña de la billetera se cambió correctamente.</translation> </message> <message> <source>Passphrase change failed</source> @@ -238,7 +241,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">Aviso: ¡La tecla de bloqueo de mayúsculas está activada!</translation> + <translation type="unfinished">Advertencia: ¡Las mayúsculas están activadas!</translation> </message> </context> <context> @@ -259,8 +262,12 @@ Signing is only possible with addresses of the type 'legacy'.</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 ha producido un error garrafal. %1Ya no podrá continuar de manera segura y abandonará.</translation> + <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> @@ -268,7 +275,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">Un error interno ocurrió. %1 intentará continuar. Este es un error inesperado que puede ser reportado de las formas que se muestran debajo,</translation> + <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> @@ -281,7 +288,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">Un error fatal ha ocurrido. Comprueba que el archivo de configuración soporta escritura, o intenta ejecutar de nuevo el programa con -nosettings</translation> + <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>%1 didn't yet exit safely…</source> @@ -292,6 +299,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">desconocido</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">"%1" integrado</translation> + </message> + <message> <source>Default system font "%1"</source> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -301,11 +312,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation type="unfinished">Ingresa una dirección de Bitcoin (Ejemplo: %1)</translation> + <translation type="unfinished">Ingresar una dirección de Bitcoin (por ejemplo, %1)</translation> </message> <message> <source>Unroutable</source> @@ -319,7 +330,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Outbound</source> <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> <message> <source>Full Relay</source> @@ -329,7 +340,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <translation type="unfinished">Retransmisión de bloques</translation> </message> <message> <source>Address Fetch</source> @@ -399,7 +410,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show general overview of wallet</source> - <translation type="unfinished">Mostrar visión general de la billetera</translation> + <translation type="unfinished">Muestra una vista general de la billetera</translation> </message> <message> <source>&Transactions</source> @@ -407,15 +418,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Browse transaction history</source> - <translation type="unfinished">Buscar historial de transacciones</translation> + <translation type="unfinished">Explora el historial de transacciones</translation> </message> <message> <source>E&xit</source> - <translation type="unfinished">S&alir</translation> + <translation type="unfinished">&Salir</translation> </message> <message> <source>Quit application</source> - <translation type="unfinished">Quitar aplicación</translation> + <translation type="unfinished">Salir del programa</translation> + </message> + <message> + <source>&About %1</source> + <translation type="unfinished">&Acerca de %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation type="unfinished">Mostrar Información sobre %1</translation> </message> <message> <source>About &Qt</source> @@ -423,27 +442,44 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Show information about Qt</source> - <translation type="unfinished">Mostrar información acerca de Qt</translation> + <translation type="unfinished">Mostrar información sobre Qt</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation type="unfinished">Modificar las opciones de configuración para %1</translation> </message> <message> <source>Create a new wallet</source> - <translation type="unfinished">Crear monedero nuevo</translation> + <translation type="unfinished">Crear una nueva billetera</translation> </message> <message> <source>&Minimize</source> - <translation type="unfinished">Minimizar</translation> + <translation type="unfinished">&Minimizar</translation> + </message> + <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> + <source>Network activity disabled.</source> + <extracomment>A substring of the tooltip.</extracomment> + <translation type="unfinished">Actividad de red deshabilitada.</translation> + </message> + <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation type="unfinished">Proxy <b>habilitado</b>: %1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> - <translation type="unfinished">Enviar monedas a una dirección Bitcoin</translation> + <translation type="unfinished">Enviar monedas a una dirección de Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Respaldar billetera en otra ubicación</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera en otra ubicación</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation type="unfinished">Cambiar frase secreta usada para la encriptación de la billetera</translation> + <translation type="unfinished">Cambiar la frase de contraseña utilizada para encriptar la billetera</translation> </message> <message> <source>&Send</source> @@ -454,28 +490,44 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">&Recibir</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Opciones…</translation> + </message> + <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&Cifrar monedero</translation> + <translation type="unfinished">&Encriptar billetera…</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> + <translation type="unfinished">Encriptar las claves privadas que pertenecen a la billetera</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Realizar copia de seguridad de la billetera...</translation> </message> <message> <source>&Change Passphrase…</source> <translation type="unfinished">&Cambiar frase de contraseña...</translation> </message> <message> + <source>Sign &message…</source> + <translation type="unfinished">Firmar &mensaje...</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Firma mensajes con tus direcciones Bitcoin para probar que eres dueño de ellas</translation> + <translation type="unfinished">Firmar mensajes con tus direcciones de Bitcoin para demostrar que te pertenecen</translation> + </message> + <message> + <source>&Verify message…</source> + <translation type="unfinished">&Verificar mensaje...</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Verificar mensajes para asegurar que estaban firmados con direcciones Bitcoin especificas</translation> + <translation type="unfinished">Verificar mensajes para asegurarte de que estén firmados con direcciones de Bitcoin concretas</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -483,15 +535,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Cerrar monedero...</translation> + <translation type="unfinished">Cerrar billetera...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Crear monedero...</translation> + <translation type="unfinished">Crear billetera...</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Cerrar todos los monederos...</translation> + <translation type="unfinished">Cerrar todas las billeteras...</translation> </message> <message> <source>&File</source> @@ -503,7 +555,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Help</source> - <translation type="unfinished">A&yuda</translation> + <translation type="unfinished">&Ayuda</translation> </message> <message> <source>Tabs toolbar</source> @@ -531,30 +583,30 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Solicitar pagos (genera codigo QR y URL's de Bitcoin)</translation> + <translation type="unfinished">Solicitar pagos (genera códigos QR y URI de tipo "bitcoin:")</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones de envÃo y etiquetas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de envÃo usadas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Muestra la lista de direcciones de recepción y etiquetas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de recepción usadas</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">Opciones de lÃnea de comandos</translation> + <translation type="unfinished">&Opciones de lÃnea de comandos</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>%n bloque procesado del historial de transacciones.</numerusform> - <numerusform>%n bloques procesados del historial de transacciones.</numerusform> + <numerusform>Se procesó %n bloque del historial de transacciones.</numerusform> + <numerusform>Se procesaron %n bloques del historial de transacciones.</numerusform> </translation> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 detrás</translation> + <translation type="unfinished">%1 atrás</translation> </message> <message> <source>Catching up…</source> @@ -562,11 +614,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">El último bloque recibido fue generado hace %1 hora(s).</translation> + <translation type="unfinished">El último bloque recibido se generó hace %1.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Transacciones después de esta no serán visibles todavÃa.</translation> + <translation type="unfinished">Las transacciones posteriores aún no están visibles.</translation> </message> <message> <source>Warning</source> @@ -578,7 +630,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Up to date</source> - <translation type="unfinished">Al dÃa</translation> + <translation type="unfinished">Actualizado</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -586,7 +638,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Cargar PSBT desde el &portapapeles...</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> @@ -594,11 +646,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Abrir consola de depuración y diagnóstico de nodo</translation> + <translation type="unfinished">Abrir la consola de depuración y diagnóstico del nodo</translation> </message> <message> <source>&Sending addresses</source> @@ -606,15 +658,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">&Direcciones de destino</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un URI de tipo "bitcoin:"</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Abrir monedero</translation> + <translation type="unfinished">Abrir billetera</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Abrir una billetera</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar billetera</translation> </message> <message> <source>Restore Wallet…</source> @@ -628,7 +688,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Migrate Wallet</source> @@ -639,20 +699,24 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Migrar una billetera</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished">Mostrar el mensaje de ayuda %1 para obtener una lista de las posibles opciones de lÃnea de comandos de Bitcoin</translation> + </message> + <message> <source>&Mask values</source> <translation type="unfinished">&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> + <translation type="unfinished">Ocultar los valores en la pestaña "Vista general"</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> <message> <source>No wallets available</source> - <translation type="unfinished">Monederos no disponibles</translation> + <translation type="unfinished">No hay billeteras disponibles</translation> </message> <message> <source>Wallet Data</source> @@ -672,13 +736,21 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> + <translation type="unfinished">Nombre de la billetera</translation> </message> <message> <source>&Window</source> <translation type="unfinished">&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> @@ -688,14 +760,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>S&how</source> - <translation type="unfinished">M&ostrar</translation> + <translation type="unfinished">&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>%n conexiones activas con la red Bitcoin</numerusform> - <numerusform>%n conexiones activas con la red Bitcoin </numerusform> + <numerusform>%n conexión activa con la red de Bitcoin.</numerusform> + <numerusform>%n conexiones activas con la red de Bitcoin.</numerusform> </translation> </message> <message> @@ -728,7 +800,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <translation type="unfinished">No se puede crear una nueva billetera, el software se compiló sin soporte sqlite (requerido para billeteras descriptivas)</translation> + <translation type="unfinished">No se puede crear una billetera nueva, ya que el software se compiló sin compatibilidad con sqlite (requerida para billeteras basadas en descriptores)</translation> </message> <message> <source>Warning: %1</source> @@ -761,7 +833,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Label: %1 </source> - <translation type="unfinished">Etiqueta: %1 + <translation type="unfinished">Etiqueta %1 </translation> </message> <message> @@ -784,7 +856,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">La generación de la clave HD está <b> desactivada </ b></translation> + <translation type="unfinished">La generación de clave HD está <b>deshabilitada</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -792,11 +864,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">La billetera está encriptada y desbloqueada recientemente</translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>desbloqueda</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">La billetera está encriptada y bloqueada recientemente</translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>bloqueda</b></translation> </message> <message> <source>Original message:</source> @@ -807,14 +879,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">Unidad en la que se muestran las cantidades. Haga clic para seleccionar otra unidad.</translation> + <translation type="unfinished">Unidad en la que se muestran los importes. Haz clic para seleccionar otra unidad.</translation> </message> </context> <context> <name>CoinControlDialog</name> <message> <source>Coin Selection</source> - <translation type="unfinished">Selección de moneda</translation> + <translation type="unfinished">Selección de monedas</translation> </message> <message> <source>Quantity:</source> @@ -822,7 +894,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Amount:</source> - <translation type="unfinished">Monto:</translation> + <translation type="unfinished">Importe:</translation> </message> <message> <source>Fee:</source> @@ -830,7 +902,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Después de tasas:</translation> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> <source>Change:</source> @@ -838,19 +910,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>(un)select all</source> - <translation type="unfinished">(de)seleccionar todo</translation> + <translation type="unfinished">(des)marcar todos</translation> </message> <message> <source>Tree mode</source> - <translation type="unfinished">Modo de árbol</translation> + <translation type="unfinished">Modo árbol</translation> </message> <message> <source>List mode</source> - <translation type="unfinished">Modo de lista</translation> + <translation type="unfinished">Modo lista</translation> </message> <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>Received with label</source> @@ -870,11 +942,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmado</translation> + <translation type="unfinished">Confirmada</translation> </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>&Copy address</source> @@ -894,7 +966,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">B&loquear importe no gastado</translation> + <translation type="unfinished">&Bloquear importe no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -910,7 +982,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de aplicar donación</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -926,7 +998,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">Puede variar en +/- %1 satoshi(s) por entrada.</translation> + <translation type="unfinished">Puede variar +/- %1 satoshi(s) por entrada.</translation> </message> <message> <source>(no label)</source> @@ -934,7 +1006,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">Enviar desde %1 (%2)</translation> + <translation type="unfinished">cambio desde %1 (%2)</translation> </message> <message> <source>(change)</source> @@ -944,6 +1016,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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">Crear billetera</translation> + </message> + <message> <source>Creating Wallet <b>%1</b>…</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 billetera <b>%1</b>…</translation> @@ -954,7 +1031,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Create wallet warning</source> - <translation type="unfinished">Advertencia de crear billetera</translation> + <translation type="unfinished">Advertencia al crear la billetera</translation> </message> <message> <source>Can't list signers</source> @@ -970,12 +1047,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <source>Load Wallets</source> <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment> - <translation type="unfinished">Cargar monederos</translation> + <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 monederos...</translation> + <translation type="unfinished">Cargando billeteras...</translation> </message> </context> <context> @@ -986,7 +1063,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Estas seguro de wue deseas migrar la billetera 1 %1 1 ?</translation> + <translation type="unfinished">¿Seguro deseas migrar la billetera <i>%1</i>?</translation> </message> <message> <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. @@ -995,10 +1072,10 @@ If this wallet contains any solvable but not watched scripts, a different and ne The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> <translation type="unfinished">La migración de la billetera la convertirá en una o más billeteras basadas en descriptores. Será necesario realizar una nueva copia de seguridad de la billetera. -Si esta billetera contiene scripts solo de lectura, se creará una nueva billetera que los contenga. -Si esta billetera contiene scripts solucionables pero no de lectura, se creará una nueva billetera diferente que los contenga. +Si esta billetera contiene scripts solo de observación, se creará una nueva billetera que los contenga. +Si esta billetera contiene scripts solucionables pero no de observación, se creará una nueva billetera diferente que los contenga. -El proceso de migración creará una copia de seguridad de la billetera antes de migrar. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En el caso de una migración incorrecta, la copia de seguridad puede restaurarse con la funcionalidad "Restore Wallet" (Restaurar billetera).</translation> +El proceso de migración creará una copia de seguridad de la billetera antes de proceder. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En caso de que la migración falle, se puede restaurar la copia de seguridad con la funcionalidad "Restaurar billetera".</translation> </message> <message> <source>Migrate Wallet</source> @@ -1014,11 +1091,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Guiones vigilantes han sido migrados a un monedero con el nombre '%1'.</translation> + <translation type="unfinished">Los scripts solo de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Solucionable pero ninguno de los guiones vigilados han sido migrados a un monedero llamados '%1'.</translation> + <translation type="unfinished">Los scripts solucionables pero no de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Migration failed</source> @@ -1032,22 +1109,26 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 sobre crear monedero</translation> + <translation type="unfinished">Advertencia al abrir billetera</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</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 billetera</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</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 <b>%1</b>...</translation> + <translation type="unfinished">Abriendo billetera <b>%1</b>...</translation> </message> </context> <context> @@ -1081,35 +1162,43 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <context> <name>WalletController</name> <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar billetera</translation> + </message> + <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">¿Estás seguro de que deseas cerrar el monedero <i>%1</i>?</translation> + <translation type="unfinished">¿Seguro deseas cerrar la billetera <i>%1</i>?</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> + <translation type="unfinished">Cerrar la billetera durante demasiado tiempo puede causar la resincronización de toda la cadena si el podado está habilitado.</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">¿Está seguro de que desea cerrar todas las billeteras?</translation> + <translation type="unfinished">¿Seguro quieres cerrar todas las billeteras?</translation> </message> </context> <context> <name>CreateWalletDialog</name> <message> + <source>Create Wallet</source> + <translation type="unfinished">Crear billetera</translation> + </message> + <message> <source>You are one step away from creating your new wallet!</source> <translation type="unfinished">Estás a un paso de crear tu nueva billetera.</translation> </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Escribe un nombre y, si lo deseas, activa las opciones avanzadas.</translation> + <translation type="unfinished">Escribe un nombre y, si quieres, activa las opciones avanzadas.</translation> </message> <message> <source>Wallet Name</source> - <translation type="unfinished">Nombre del monedero</translation> + <translation type="unfinished">Nombre de la billetera </translation> </message> <message> <source>Wallet</source> @@ -1117,7 +1206,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">Encriptar la billetera. La billetera será encriptada con una contraseña de tu elección.</translation> + <translation type="unfinished">Encriptar la billetera. La billetera se encriptará con una frase de contraseña de tu elección.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation type="unfinished">Encriptar billetera</translation> + </message> + <message> + <source>Advanced Options</source> + <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">Desactivar las claves privadas para esta billetera. Las billeteras con claves privadas desactivadas no tendrán claves privadas y no podrán tener ninguna semilla HD ni claves privadas importadas. Esto es ideal para billeteras solo de observación.</translation> </message> <message> <source>Disable Private Keys</source> @@ -1125,11 +1226,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Crea una billetera en blanco. Las billeteras en blanco inicialmente no tienen llaves privadas ni scripts. Las llaves privadas y las direcciones pueden ser importadas o se puede establecer una semilla HD más tarde.</translation> </message> <message> <source>Make Blank Wallet</source> - <translation type="unfinished">Crear billetera vacÃa</translation> + <translation type="unfinished">Crear billetera en blanco</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">Usa un dispositivo de firma externo, por ejemplo, una billetera de hardware. Configura primero el script del firmante externo en las preferencias de la billetera.</translation> </message> <message> <source>External signer</source> @@ -1142,7 +1247,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> </context> <context> @@ -1157,11 +1262,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished">La etiqueta asociada con esta entrada de la lista de direcciones</translation> + <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 de la lista de direcciones. Esta puede ser modificada solo para el envÃo de direcciones.</translation> + <translation type="unfinished">La dirección asociada con esta entrada en la lista de direcciones. Solo se puede modificar para las direcciones de envÃo.</translation> </message> <message> <source>&Address</source> @@ -1181,22 +1286,30 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">La dirección ingresada "%1" no es una dirección de 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 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 el monedero.</translation> + <translation type="unfinished">No se pudo desbloquear la billetera.</translation> </message> <message> <source>New key generation failed.</source> - <translation type="unfinished">Ha fallado la generación de la nueva clave.</translation> + <translation type="unfinished">Error al generar clave nueva.</translation> </message> </context> <context> <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation type="unfinished">Un nuevo directorio de datos será creado.</translation> + <translation type="unfinished">Se creará un nuevo directorio de datos.</translation> </message> <message> <source>name</source> @@ -1204,15 +1317,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <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> + <translation type="unfinished">El directorio ya existe. Agrega %1 si deseas 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> + <translation type="unfinished">Ruta de acceso existente, pero 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> + <translation type="unfinished">No se puede crear un directorio de datos aquÃ.</translation> </message> </context> <context> @@ -1227,15 +1340,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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>(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 needed for full chain)</numerusform> - <numerusform>(%n GB needed for full chain)</numerusform> + <numerusform>(%n GB necesario para completar la cadena)</numerusform> + <numerusform>(%n GB necesarios para completar la cadena)</numerusform> </translation> </message> <message> @@ -1243,8 +1356,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Elegir directorio de datos</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">Se almacenará al menos %1 GB de información en este directorio, que aumentará con el tiempo.</translation> + </message> + <message> <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> + <translation type="unfinished">Se almacenará aproximadamente %1 GB de información en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1260,27 +1377,35 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">La billetera también se almacenará en este directorio.</translation> </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">Error: Directorio de datos especificado "%1" no puede ser creado.</translation> + <translation type="unfinished">Error: No se puede crear el directorio de datos especificado "%1" .</translation> </message> <message> <source>Welcome</source> - <translation type="unfinished">Bienvenido</translation> + <translation type="unfinished">Te damos la bienvenida</translation> </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">Bienvenido a %1.</translation> + <translation type="unfinished">Te damos la bienvenida 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> + <translation type="unfinished">Como es la primera vez que se ejecuta el programa, puedes elegir dónde %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> + <translation type="unfinished">Limitar el almacenamiento de la 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">Para revertir esta configuración, se debe descargar de nuevo la cadena de bloques completa. Es más rápido descargar la cadena completa y podarla después. Desactiva algunas funciones avanzadas.</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">La sincronización inicial consume muchos recursos y es posible que exponga problemas de hardware en la computadora que anteriormente pasaron desapercibidos. Cada vez que ejecutes %1, seguirá descargando desde el punto en el que quedó.</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> @@ -1288,15 +1413,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Si elegiste la opción de limitar el almacenamiento de la cadena de bloques (podado), los datos históricos se deben descargar y procesar de igual manera, pero se eliminarán después para disminuir el uso del disco.</translation> </message> <message> <source>Use the default data directory</source> - <translation type="unfinished">Usar el directorio de datos por defecto</translation> + <translation type="unfinished">Usar 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> + <translation type="unfinished">Usar un directorio de datos personalizado:</translation> </message> </context> <context> @@ -1315,38 +1440,69 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> </context> <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 apagues la computadora hasta que desaparezca esta ventana.</translation> + </message> +</context> +<context> <name>ModalOverlay</name> <message> <source>Form</source> - <translation type="unfinished">Desde</translation> + <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> + <translation type="unfinished">Es posible que las transacciones recientes aún no sean visibles y, por lo tanto, el saldo de la billetera podrÃa ser incorrecto. Esta información será correcta una vez que la billetera haya terminado de sincronizarse con la red de Bitcoin, como se detalla abajo.</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á si se intenta gastar bitcoins afectados por las transacciones que aún no se muestran.</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">Numero de bloques pendientes</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> <message> + <source>Progress</source> + <translation type="unfinished">Progreso</translation> + </message> + <message> <source>Progress increase per hour</source> - <translation type="unfinished">Incremento del progreso por hora</translation> + <translation type="unfinished">Avance del progreso por hora</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation type="unfinished">Tiempo estimado restante hasta la sincronización</translation> + </message> + <message> + <source>Hide</source> + <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> + <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 cabeceras (%1, %2%)…</translation> + <translation type="unfinished">Desconocido. Sincronizando encabezados (%1, %2%)…</translation> </message> <message> <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> @@ -1362,7 +1518,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> </context> <context> @@ -1372,16 +1528,28 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Opciones</translation> </message> <message> + <source>&Main</source> + <translation type="unfinished">&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>&Start %1 on system login</source> - <translation type="unfinished">&Iniciar %1 al iniciar el sistema</translation> + <translation type="unfinished">&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">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> + <translation type="unfinished">Al activar el podado, 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 &database cache</source> + <translation type="unfinished">Tamaño de la caché de la &base de datos</translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">Número de hilos de &verificación de scripts</translation> + <translation type="unfinished">Número de subprocesos de &verificación de scripts</translation> </message> <message> <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> @@ -1389,15 +1557,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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 (ej. IPv4: 127.0.0.1 / IPv6: ::1)</translation> + <translation type="unfinished">Dirección IP del proxy (por 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 suministrado se utiliza para llegar a los 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">Minimice en lugar de salir de la aplicación cuando la ventana esté cerrada. Cuando esta opción está habilitada, la aplicación se cerrará solo después de seleccionar Salir en el menú.</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 solo se cerrará después de seleccionar "Salir" en el menú.</translation> </message> <message> <source>Font in the Overview tab: </source> - <translation type="unfinished">Fuente en la pestaña Resumen:</translation> + <translation type="unfinished">Fuente en la pestaña "Vista general":</translation> </message> <message> <source>Options set in this dialog are overridden by the command line:</source> @@ -1413,7 +1585,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Reset all client options to default.</source> - <translation type="unfinished">Restablecer todas las opciones del cliente a las predeterminadas.</translation> + <translation type="unfinished">Restablecer todas las opciones del cliente a los valores predeterminados.</translation> </message> <message> <source>&Reset Options</source> @@ -1439,7 +1611,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Establece el número de subprocesos 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, <0 = leave that many cores free)</source> @@ -1448,7 +1620,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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 los comandos JSON-RPC.</translation> </message> <message> <source>Enable R&PC server</source> @@ -1457,12 +1629,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>W&allet</source> - <translation type="unfinished">Billetera</translation> + <translation type="unfinished">&Billetera</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> + <translation type="unfinished">Si se resta o no la comisión del importe por defecto.</translation> </message> <message> <source>Subtract &fee from amount by default</source> @@ -1474,8 +1646,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Experto</translation> </message> <message> + <source>Enable coin &control features</source> + <translation type="unfinished">Habilitar funciones de &control de monedas</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 deshabilita 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 cómo se calcula su saldo.</translation> + <translation type="unfinished">Si deshabilitas el gasto del cambio sin confirmar, no se puede usar el cambio de una transacción hasta que esta tenga al menos una confirmación. Esto también afecta cómo se calcula el saldo.</translation> </message> <message> <source>&Spend unconfirmed change</source> @@ -1484,12 +1660,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <message> <source>Enable &PSBT controls</source> <extracomment>An options window setting to enable PSBT controls.</extracomment> - <translation type="unfinished">Activar controles de &PSBT</translation> + <translation type="unfinished">Activar controles de &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">Si se muestran los controles de PSBT.</translation> + <translation type="unfinished">Si se muestran los controles de TBPF.</translation> </message> <message> <source>External Signer (e.g. hardware wallet)</source> @@ -1501,11 +1677,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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 si el router admite UPnP y está activado.</translation> + <translation type="unfinished">Abrir automáticamente el puerto del cliente de Bitcoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado.</translation> </message> <message> <source>Map port using &UPnP</source> - <translation type="unfinished">Mapear el puerto usando &UPnP</translation> + <translation type="unfinished">Asignar puerto usando &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> @@ -1516,16 +1692,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Asignar puerto usando NA&T-PMP</translation> </message> <message> + <source>Accept connections from outside.</source> + <translation type="unfinished">Aceptar conexiones externas.</translation> + </message> + <message> <source>Allow incomin&g connections</source> - <translation type="unfinished">Permitir conexiones entrantes</translation> + <translation type="unfinished">&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> + <translation type="unfinished">Conectarse a la red de Bitcoin a través de un proxy SOCKS5.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation type="unfinished">&Conectarse a través del proxy SOCKS5 (proxy predeterminado):</translation> </message> <message> <source>Proxy &IP:</source> - <translation type="unfinished">Dirección &IP del proxy:</translation> + <translation type="unfinished">&IP del proxy:</translation> </message> <message> <source>&Port:</source> @@ -1533,11 +1717,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation type="unfinished">Puerto del servidor proxy (ej. 9050)</translation> + <translation type="unfinished">Puerto del proxy (p. ej., 9050)</translation> </message> <message> <source>Used for reaching peers via:</source> - <translation type="unfinished">Utilizado para llegar a los compañeros a través de:</translation> + <translation type="unfinished">Usado para conectarse con pares a través de:</translation> </message> <message> <source>&Window</source> @@ -1553,35 +1737,35 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Show only a tray icon after minimizing the window.</source> - <translation type="unfinished">Minimizar la ventana a la bandeja de iconos del sistema.</translation> + <translation type="unfinished">Mostrar solo un Ãcono de bandeja después de minimizar la ventana.</translation> </message> <message> <source>&Minimize to the tray instead of the taskbar</source> - <translation type="unfinished">&Minimizar a la bandeja en vez de a la barra de tareas</translation> + <translation type="unfinished">&Minimizar a la bandeja en vez de la barra de tareas</translation> </message> <message> <source>M&inimize on close</source> - <translation type="unfinished">M&inimizar al cerrar</translation> + <translation type="unfinished">&Minimizar al cerrar</translation> </message> <message> <source>&Display</source> - <translation type="unfinished">&Interfaz</translation> + <translation type="unfinished">&Visualización</translation> </message> <message> <source>User Interface &language:</source> - <translation type="unfinished">I&dioma de la interfaz de usuario</translation> + <translation type="unfinished">&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> + <translation type="unfinished">El idioma de la interfaz de usuario puede establecerse aquÃ. Esta configuración surtirá efecto después de reiniciar %1.</translation> </message> <message> <source>&Unit to show amounts in:</source> - <translation type="unfinished">Mostrar las cantidades en la &unidad:</translation> + <translation type="unfinished">&Unidad en la que se muestran los 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> + <translation type="unfinished">Elegir la unidad de subdivisión predeterminada para mostrar en la interfaz y al enviar 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> @@ -1593,28 +1777,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Whether to show coin control features or not.</source> - <translation type="unfinished">Mostrar o no caracterÃsticas de control de moneda</translation> + <translation type="unfinished">Si se muestran o no las funcionalidades de control de monedas.</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> + <translation type="unfinished">Conectarse a la red de Bitcoin a través de un proxy SOCKS5 independiente para los servicios onion de Tor.</translation> </message> <message> <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> <translation type="unfinished">Usar un proxy SOCKS&5 independiente para comunicarse con pares a través de los servicios onion de Tor:</translation> </message> <message> - <source>&OK</source> - <translation type="unfinished">&Aceptar</translation> - </message> - <message> <source>&Cancel</source> <translation type="unfinished">&Cancelar</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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> <message> <source>default</source> @@ -1627,12 +1807,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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">Reinicio del cliente para activar cambios.</translation> + <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> @@ -1642,7 +1822,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">El cliente se cerrará. ¿Quieres continuar?</translation> </message> <message> <source>Configuration options</source> @@ -1652,7 +1832,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">El archivo de configuración se usa para especificar opciones avanzadas del usuario, que remplazan la configuración de la GUI. Además, las opciones de la lÃnea de comandos remplazarán este archivo de configuración.</translation> </message> <message> <source>Continue</source> @@ -1664,15 +1844,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>The configuration file could not be opened.</source> - <translation type="unfinished">El archivo de configuración no se pudo abrir.</translation> + <translation type="unfinished">No se pudo abrir el archivo de configuración.</translation> </message> <message> <source>This change would require a client restart.</source> - <translation type="unfinished">Este cambio requiere reinicio por parte del cliente.</translation> + <translation type="unfinished">Estos cambios requieren reiniciar el cliente.</translation> </message> <message> <source>The supplied proxy address is invalid.</source> - <translation type="unfinished">La dirección proxy indicada es inválida.</translation> + <translation type="unfinished">La dirección del proxy proporcionada es inválida.</translation> </message> </context> <context> @@ -1686,11 +1866,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <name>OverviewPage</name> <message> <source>Form</source> - <translation type="unfinished">Desde</translation> + <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 Bitcoin después de que se haya establecido una conexión, pero este proceso aún no se ha completado.</translation> + <translation type="unfinished">La información mostrada puede estar desactualizada. La billetera 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 de observación:</translation> </message> <message> <source>Available:</source> @@ -1698,7 +1882,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current spendable balance</source> - <translation type="unfinished">Su balance actual gastable</translation> + <translation type="unfinished">Tu saldo disponible para gastar actualmente</translation> </message> <message> <source>Pending:</source> @@ -1706,15 +1890,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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">Total de transacciones que deben ser confirmadas, y que no cuentan con el balance gastable necesario</translation> + <translation type="unfinished">Total de transacciones que aún se deben confirmar y que no se contabilizan dentro del saldo disponible para gastar</translation> </message> <message> <source>Immature:</source> - <translation type="unfinished">No disponible:</translation> + <translation type="unfinished">Inmaduro:</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> + <translation type="unfinished">Saldo minado que aún no ha madurado</translation> </message> <message> <source>Balances</source> @@ -1722,15 +1906,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current total balance</source> - <translation type="unfinished">Su balance actual total</translation> + <translation type="unfinished">Tu saldo total actual</translation> </message> <message> <source>Your current balance in watch-only addresses</source> - <translation type="unfinished">Tu saldo actual en solo ver direcciones</translation> + <translation type="unfinished">Tu saldo actual en direcciones solo de observación</translation> </message> <message> <source>Spendable:</source> - <translation type="unfinished">Disponible:</translation> + <translation type="unfinished">Gastable:</translation> </message> <message> <source>Recent transactions</source> @@ -1738,22 +1922,26 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation type="unfinished">Transacciones sin confirmar a direcciones de observación</translation> + <translation type="unfinished">Transacciones sin confirmar hacia direcciones solo 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 solo de observación que aún no ha madurado</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation type="unfinished">Saldo total actual en direcciones de solo observación</translation> + <translation type="unfinished">Saldo total actual en direcciones solo de observación</translation> </message> <message> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->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->Ocultar valores.</translation> + <translation type="unfinished">Modo de privacidad activado para la pestaña de vista general. Para mostrar los valores, anula la selección de "Configuración->Ocultar valores".</translation> </message> </context> <context> <name>PSBTOperationsDialog</name> <message> <source>PSBT Operations</source> - <translation type="unfinished">Operaciones PSBT</translation> + <translation type="unfinished">Operaciones TBPF</translation> </message> <message> <source>Sign Tx</source> @@ -1789,7 +1977,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Could not sign any more inputs.</source> - <translation type="unfinished">No se pudo firmar más entradas.</translation> + <translation type="unfinished">No se pudieron firmar más entradas.</translation> </message> <message> <source>Signed %1 inputs, but more signatures are still required.</source> @@ -1813,7 +2001,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>PSBT copied to clipboard.</source> - <translation type="unfinished">PSBT copiada al portapapeles.</translation> + <translation type="unfinished">TBPF copiada al portapapeles.</translation> </message> <message> <source>Save Transaction Data</source> @@ -1826,7 +2014,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT guardada en en el disco.</translation> + <translation type="unfinished">TBPF guardada en el disco.</translation> </message> <message> <source>Sends %1 to %2</source> @@ -1846,7 +2034,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>or</source> @@ -1858,7 +2046,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Falta información sobre las entradas de la transacción.</translation> </message> <message> <source>Transaction still needs signature(s).</source> @@ -1880,16 +2068,20 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> - </context> + <message> + <source>Transaction status is unknown.</source> + <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 petición de pago</translation> + <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 pudo iniciar bitcoin: manejador de pago-al-clic</translation> + <translation type="unfinished">No se puede iniciar el controlador "bitcoin: click-to-pay"</translation> </message> <message> <source>URI handling</source> @@ -1897,7 +2089,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">"bitcoin://" no es un URI válido. Usa "bitcoin:" en su lugar.</translation> </message> <message> <source>Cannot process payment request because BIP70 is not supported. @@ -1905,11 +2097,15 @@ Due to widespread security flaws in BIP70 it's strongly recommended that any mer 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> +Si recibes este error, debes solicitar al comerciante que te 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">No se puede analizar el URI. Esto se puede deber a una dirección de Bitcoin inválida o a parámetros de URI con formato incorrecto.</translation> </message> <message> <source>Payment request file handling</source> - <translation type="unfinished">Manejo del archivo de solicitud de pago</translation> + <translation type="unfinished">Gestión del archivo de solicitud de pago</translation> </message> </context> <context> @@ -1927,12 +2123,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Antigüedad</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> </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">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>Received</source> @@ -1942,7 +2143,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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">Direccion</translation> + <translation type="unfinished">Dirección</translation> </message> <message> <source>Type</source> @@ -1962,7 +2163,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>Outbound</source> <extracomment>An Outbound Connection to a Peer.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> </context> <context> @@ -1973,15 +2174,15 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Copy Image</source> - <translation type="unfinished">Copiar imagen</translation> + <translation type="unfinished">&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> + <translation type="unfinished">El URI resultante es demasiado largo, asà que trata de reducir el texto de la etiqueta o el mensaje.</translation> </message> <message> <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">Error al codificar la URI en el código QR.</translation> + <translation type="unfinished">Fallo al codificar URI en código QR.</translation> </message> <message> <source>QR code support not available.</source> @@ -2009,23 +2210,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Information</source> - <translation type="unfinished">Información</translation> + <translation type="unfinished">&Información</translation> + </message> + <message> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de datos, usa la opción "%1".</translation> </message> <message> <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <translation type="unfinished">Directorio de bloques</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de bloques, usa la opción "%1".</translation> </message> <message> <source>Startup time</source> - <translation type="unfinished">Hora de inicio</translation> + <translation type="unfinished">Tiempo de inicio</translation> </message> <message> <source>Network</source> @@ -2045,19 +2250,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Memory Pool</source> - <translation type="unfinished">Grupo de memoria</translation> + <translation type="unfinished">Pool de memoria</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation type="unfinished">Número total de transacciones</translation> </message> <message> <source>Memory usage</source> - <translation type="unfinished">Memoria utilizada</translation> + <translation type="unfinished">Uso de memoria</translation> </message> <message> <source>Wallet: </source> - <translation type="unfinished">Monedero:</translation> + <translation type="unfinished">Billetera:</translation> + </message> + <message> + <source>(none)</source> + <translation type="unfinished">(ninguna)</translation> </message> <message> <source>&Reset</source> - <translation type="unfinished">&Reestablecer</translation> + <translation type="unfinished">&Restablecer</translation> </message> <message> <source>Received</source> @@ -2065,7 +2278,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Sent</source> - <translation type="unfinished">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>&Peers</source> @@ -2089,13 +2302,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Cadena de identificación de la sesión BIP324 en formato hexadecimal, si existe.</translation> + <translation type="unfinished">Cadena de identificador de la sesión BIP324 en formato hexadecimal, si existe.</translation> </message> <message> <source>Session ID</source> <translation type="unfinished">Identificador de sesión</translation> </message> <message> + <source>Version</source> + <translation type="unfinished">Versión</translation> + </message> + <message> <source>Whether we relay transactions to this peer.</source> <translation type="unfinished">Si retransmitimos las transacciones a este par.</translation> </message> @@ -2105,13 +2322,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Starting Block</source> - <translation type="unfinished">Bloque de inicio</translation> + <translation type="unfinished">Bloque inicial</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> @@ -2131,17 +2352,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Retransmisión de direcciones</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> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se procesaron (excluye las direcciones desestimadas 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> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se desestimaron (no se procesaron) debido a la limitación de volumen.</translation> </message> <message> <source>Addresses Processed</source> @@ -2151,7 +2372,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Direcciones desestimadas por limitación de volumen</translation> </message> <message> <source>User Agent</source> @@ -2159,7 +2380,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Current block height</source> @@ -2167,15 +2388,19 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> + <translation type="unfinished">Abrir el archivo de registro de depuración %1 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> </message> <message> <source>Decrease font size</source> - <translation type="unfinished">Reducir el tamaño de la fuente</translation> + <translation type="unfinished">Disminuir tamaño de fuente</translation> </message> <message> <source>Increase font size</source> - <translation type="unfinished">Aumentar el tamaño de la fuente</translation> + <translation type="unfinished">Aumentar tamaño de fuente</translation> + </message> + <message> + <source>Permissions</source> + <translation type="unfinished">Permisos</translation> </message> <message> <source>The direction and type of peer connection: %1</source> @@ -2195,13 +2420,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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> + <translation type="unfinished">Retransmisión de bloques compactos BIP152 en 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">Tiempo de 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> @@ -2220,21 +2449,29 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Last Receive</source> - <translation type="unfinished">Ultima recepción</translation> + <translation type="unfinished">Última recepción</translation> </message> <message> <source>Ping Time</source> - <translation type="unfinished">Tiempo de Ping</translation> + <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> + <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">Desfase temporal</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Hora del último bloque</translation> </message> @@ -2248,15 +2485,15 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Network Traffic</source> - <translation type="unfinished">&Tráfico de Red</translation> + <translation type="unfinished">&Tráfico de red</translation> </message> <message> <source>Totals</source> - <translation type="unfinished">Total:</translation> + <translation type="unfinished">Totales</translation> </message> <message> <source>Debug log file</source> - <translation type="unfinished">Archivo de registro de depuración</translation> + <translation type="unfinished">Archivo del registro de depuración</translation> </message> <message> <source>Clear console</source> @@ -2308,7 +2545,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>v1: unencrypted, plaintext transport protocol</source> <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">v1: protocolo de transporte de texto simple sin cifrar</translation> + <translation type="unfinished">v1: protocolo de transporte de texto simple sin encriptar</translation> </message> <message> <source>v2: BIP324 encrypted transport protocol</source> @@ -2325,7 +2562,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>no high bandwidth relay selected</source> - <translation type="unfinished">Ninguna transmisión de banda ancha seleccionada</translation> + <translation type="unfinished">No se seleccionó la retransmisión de banda ancha</translation> </message> <message> <source>&Copy address</source> @@ -2333,21 +2570,33 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">&Copiar dirección</translation> </message> <message> + <source>&Disconnect</source> + <translation type="unfinished">&Desconectar</translation> + </message> + <message> <source>1 &hour</source> - <translation type="unfinished">1 hora</translation> + <translation type="unfinished">1 &hora</translation> </message> <message> <source>1 d&ay</source> <translation type="unfinished">1 &dÃa</translation> </message> <message> + <source>1 &week</source> + <translation type="unfinished">1 &semana</translation> + </message> + <message> + <source>1 &year</source> + <translation type="unfinished">1 &año</translation> + </message> + <message> <source>&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">&Copiar IP/Máscara de red</translation> </message> <message> <source>&Unban</source> - <translation type="unfinished">&Desbloquear</translation> + <translation type="unfinished">&Levantar prohibición</translation> </message> <message> <source>Network activity disabled</source> @@ -2355,13 +2604,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Executing command without any wallet</source> - <translation type="unfinished">Ejecutar comando sin monedero</translation> + <translation type="unfinished">Ejecutar comando sin ninguna billetera</translation> </message> <message> <source>Node window - [%1]</source> <translation type="unfinished">Ventana de nodo - [%1]</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. @@ -2370,12 +2623,13 @@ 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">Bienvenido a la consola RPC -%1. Utiliza las flechas arriba y abajo para navegar por el historial, y %2 para borrar la pantalla. + <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 un resumen de los comandos disponibles. Para más información sobre cómo usar esta consola, escribe %6. +Escribe %5 para ver los comandos disponibles. +Para obtener más información sobre cómo usar esta consola, escribe %6. -%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> +%7 ADVERTENCIA: Los estafadores suelen decirles a los usuarios que escriban comandos aquà para robarles el contenido de sus billeteras. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation> </message> <message> <source>Executing…</source> @@ -2392,11 +2646,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Yes</source> - <translation type="unfinished">Si</translation> + <translation type="unfinished">SÃ</translation> </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>From</source> @@ -2404,11 +2658,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Ban for</source> - <translation type="unfinished">Bloqueo para</translation> + <translation type="unfinished">Prohibir por</translation> </message> <message> <source>Never</source> - <translation type="unfinished">nunca</translation> + <translation type="unfinished">Nunca</translation> </message> <message> <source>Unknown</source> @@ -2419,7 +2673,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation type="unfinished">Monto:</translation> + <translation type="unfinished">&Importe:</translation> </message> <message> <source>&Label:</source> @@ -2427,27 +2681,27 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>&Message:</source> - <translation type="unfinished">Mensaje:</translation> + <translation type="unfinished">&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 adjunto a la solicitud de pago, que será mostrado cuando la solicitud sea abierta. Nota: Este mensaje no será enviado con el pago a través de la red Bitcoin.</translation> + <translation type="unfinished">Mensaje opcional para adjuntar a la solicitud de pago, que se mostrará cuando se abra la solicitud. Nota: Este 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">Una etiqueta opcional para asociar con la nueva dirección de recepción</translation> + <translation type="unfinished">Una 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 <b>optional</b>.</source> - <translation type="unfinished">Use este formulario para solicitar pagos. Todos los campos son <b> opcionales </ b>.</translation> + <translation type="unfinished">Usa este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>.</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> + <translation type="unfinished">Un importe opcional para solicitar. Déjalo vacÃo o ingresa cero para no solicitar un importe 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> + <translation type="unfinished">Una etiqueta opcional para asociar con la nueva dirección de recepción (puedes usarla 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> @@ -2455,23 +2709,23 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>&Create new receiving address</source> - <translation type="unfinished">&Crear una nueva dirección de recepción</translation> + <translation type="unfinished">&Crear 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> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Clear</source> - <translation type="unfinished">Limpiar</translation> + <translation type="unfinished">Borrar</translation> </message> <message> <source>Requested payments history</source> - <translation type="unfinished">Historial de pagos solicitado</translation> + <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">Muestra la petición seleccionada (También doble clic)</translation> + <translation type="unfinished">Mostrar la solicitud seleccionada (equivale a hacer doble clic en una entrada)</translation> </message> <message> <source>Show</source> @@ -2479,7 +2733,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Remove the selected entries from the list</source> - <translation type="unfinished">Borrar de la lista las direcciónes actualmente seleccionadas</translation> + <translation type="unfinished">Eliminar las entradas seleccionadas de la lista</translation> </message> <message> <source>Remove</source> @@ -2523,11 +2777,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Could not unlock wallet.</source> - <translation type="unfinished">No se pudo desbloquear el monedero.</translation> + <translation type="unfinished">No se pudo desbloquear la billetera.</translation> </message> <message> <source>Could not generate new %1 address</source> - <translation type="unfinished">No se ha podido generar una nueva dirección %1</translation> + <translation type="unfinished">No se pudo generar nueva dirección %1</translation> </message> </context> <context> @@ -2537,20 +2791,32 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Solicitar pago a...</translation> </message> <message> + <source>Address:</source> + <translation type="unfinished">Dirección:</translation> + </message> + <message> <source>Amount:</source> - <translation type="unfinished">Monto:</translation> + <translation type="unfinished">Importe:</translation> + </message> + <message> + <source>Label:</source> + <translation type="unfinished">Etiqueta:</translation> </message> <message> <source>Message:</source> <translation type="unfinished">Mensaje:</translation> </message> <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> <source>Copy &URI</source> <translation type="unfinished">Copiar &URI</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished">&Copiar Dirección</translation> + <translation type="unfinished">Copiar &dirección</translation> </message> <message> <source>&Verify</source> @@ -2558,7 +2824,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, por ejemplo, en la pantalla de una billetera de hardware</translation> + <translation type="unfinished">Verificar esta dirección, por ejemplo, en la pantalla de una billetera de hardware.</translation> </message> <message> <source>&Save Image…</source> @@ -2566,7 +2832,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Payment information</source> - <translation type="unfinished">Información de pago</translation> + <translation type="unfinished">Información del pago</translation> </message> <message> <source>Request payment to %1</source> @@ -2581,7 +2847,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Label</source> - <translation type="unfinished">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> </message> <message> <source>Message</source> @@ -2593,11 +2859,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>(no message)</source> - <translation type="unfinished">(Ningun mensaje)</translation> + <translation type="unfinished">(sin mensaje)</translation> </message> <message> <source>(no amount requested)</source> - <translation type="unfinished">(sin importe solicitado)</translation> + <translation type="unfinished">(no se solicitó un importe)</translation> </message> <message> <source>Requested</source> @@ -2612,15 +2878,15 @@ 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">Funciones de control de monedas</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished">Seleccionado automaticamente</translation> + <translation type="unfinished">seleccionado automáticamente</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished">Fondos insuficientes!</translation> + <translation type="unfinished">Fondos insuficientes</translation> </message> <message> <source>Quantity:</source> @@ -2628,7 +2894,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Amount:</source> - <translation type="unfinished">Monto:</translation> + <translation type="unfinished">Importe:</translation> </message> <message> <source>Fee:</source> @@ -2636,7 +2902,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>After Fee:</source> - <translation type="unfinished">Después de tasas:</translation> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> <source>Change:</source> @@ -2644,11 +2910,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </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> + <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 propia</translation> + <translation type="unfinished">Dirección de cambio personalizada</translation> </message> <message> <source>Transaction Fee:</source> @@ -2656,11 +2922,19 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </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> + <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> - <translation type="unfinished">Advertencia: En este momento no se puede estimar la cuota.</translation> + <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> @@ -2672,15 +2946,15 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Send to multiple recipients at once</source> - <translation type="unfinished">Enviar a múltiples destinatarios de una vez</translation> + <translation type="unfinished">Enviar a múltiples destinatarios a la vez</translation> </message> <message> <source>Add &Recipient</source> - <translation type="unfinished">Añadir &destinatario</translation> + <translation type="unfinished">Agregar &destinatario</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished">Limpiar todos los campos del formulario</translation> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Inputs…</source> @@ -2708,19 +2982,27 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">Una comisión demasiado pequeña puede resultar en una transacción que nunca será confirmada (leer herramientas de información).</translation> + <translation type="unfinished">Si la comisión es demasiado baja, es posible que la transacción nunca se confirme (leer la información en pantalla).</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 "Remplazar 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> + <translation type="unfinished">Con la función "Remplazar 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 &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>Balance:</source> @@ -2740,7 +3022,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>Copy fee</source> @@ -2748,7 +3030,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de aplicar donación</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -2759,22 +3041,34 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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">Firmar en el dispositivo</translation> </message> <message> <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Conecta tu monedero externo primero.</translation> + <translation type="unfinished">Conecta primero tu billetera de hardware.</translation> </message> <message> <source>Set external signer script path in Options -> Wallet</source> <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Configura una ruta externa al script en Opciones -> Monedero</translation> + <translation type="unfinished">Establecer la ruta al script del firmante externo en "Opciones -> Billetera"</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation type="unfinished">&Crear 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> + <translation type="unfinished">Crea una transacción de Bitcoin parcialmente firmada (TBPF) para usarla, por ejemplo, con una billetera %1 sin conexión o una billetera de hardware compatible con TBPF.</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation type="unfinished">%1 a '%2'</translation> </message> <message> <source>%1 to %2</source> @@ -2786,17 +3080,17 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Sign failed</source> - <translation type="unfinished">La firma falló</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <translation type="unfinished">Error de firmante externo</translation> </message> <message> <source>Save Transaction Data</source> @@ -2810,7 +3104,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">TBPF guardado </translation> + <translation type="unfinished">TBPF guardada</translation> </message> <message> <source>External balance:</source> @@ -2822,11 +3116,16 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Puedes aumentar la comisión después (indica "Remplazar 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 (TBPF) que puedes guardar o copiar y, luego, firmar; por ejemplo, una billetera %1 fuera de lÃnea o una billetera de hardware compatible con TBPF.</translation> </message> <message> <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 desde monedero '%2'</translation> + <translation type="unfinished">%1 desde billetera "%2"</translation> </message> <message> <source>Do you want to create this transaction?</source> @@ -2836,12 +3135,12 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">Revisa la transacción. Puedes crear y enviar esta transacción de Bitcoin parcialmente firmada (TBPF), 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 TBPF.</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, revisa tu transacción</translation> + <translation type="unfinished">Revisa la transacción.</translation> </message> <message> <source>Transaction fee</source> @@ -2849,11 +3148,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">No indica remplazar-por-comisión, BIP-125.</translation> + <translation type="unfinished">No indica "Remplazar por comisión", BIP-125.</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>Unsigned Transaction</source> @@ -2863,11 +3162,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">Se copió la PSBT al portapapeles. También puedes guardarla.</translation> + <translation type="unfinished">Se copió la TBPF al portapapeles. También puedes guardarla.</translation> </message> <message> <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT guardada en el disco</translation> + <translation type="unfinished">TBPF guardada en el disco</translation> </message> <message> <source>Confirm send coins</source> @@ -2883,15 +3182,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">La cantidad por pagar tiene que ser mayor de 0.</translation> + <translation type="unfinished">El importe por pagar tiene que ser mayor que 0.</translation> </message> <message> <source>The amount exceeds your balance.</source> - <translation type="unfinished">La cantidad sobrepasa su saldo.</translation> + <translation type="unfinished">El importe sobrepasa el 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 tasa de envÃo de %1</translation> + <translation type="unfinished">El total sobrepasa el saldo cuando se incluye la comisión de transacción de %1.</translation> </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> @@ -2899,34 +3198,34 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Transaction creation failed!</source> - <translation type="unfinished">¡Ha fallado la creación de la transacción!</translation> + <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 absurda-mente alta.</translation> + <translation type="unfinished">Una comisión mayor que %1 se considera absurdamente alta.</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Estimado para comenzar confirmación dentro de %n bloque.</numerusform> - <numerusform>Estimado para comenzar confirmación dentro de %n bloques.</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> <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">Alerta: Dirección de Bitcoin inválida</translation> + <translation type="unfinished">Advertencia: Dirección de Bitcoin inválida</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation type="unfinished">Alerta: Dirección de Bitcoin inválida</translation> + <translation type="unfinished">Advertencia: Dirección de cambio desconocida</translation> </message> <message> <source>Confirm custom change address</source> - <translation type="unfinished">Confirmar dirección de cambio personalizada</translation> + <translation type="unfinished">Confirmar la 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> + <translation type="unfinished">La dirección que seleccionaste para el cambio no es parte de esta billetera. Una parte o la totalidad de los fondos en la billetera se enviará a esta dirección. ¿Seguro deseas continuar?</translation> </message> <message> <source>(no label)</source> @@ -2937,11 +3236,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation type="unfinished">Monto:</translation> + <translation type="unfinished">&Importe:</translation> </message> <message> <source>Pay &To:</source> - <translation type="unfinished">&Pagar a:</translation> + <translation type="unfinished">Pagar &a:</translation> </message> <message> <source>&Label:</source> @@ -2949,25 +3248,33 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Choose previously used address</source> - <translation type="unfinished">Escoger dirección previamente usada</translation> + <translation type="unfinished">Seleccionar dirección usada anteriormente</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> + <translation type="unfinished">La dirección de 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> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> <message> <source>Remove this entry</source> - <translation type="unfinished">Eliminar esta transacción</translation> + <translation type="unfinished">Eliminar 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 importe que se envÃa. El destinatario recibirá menos bitcoins que los que ingreses en el campo del importe. Si se seleccionan varios destinatarios, la comisión se dividirá por igual.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation type="unfinished">&Restar la comisión del importe</translation> + </message> + <message> <source>Use available balance</source> <translation type="unfinished">Usar el saldo disponible</translation> </message> @@ -2977,11 +3284,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Ingresar una etiqueta para esta dirección a fin de agregarla 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á enviado a través de la red de Bitcoin.</translation> + <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> @@ -2999,7 +3306,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Firmas - Firmar / verificar un mensaje</translation> + <translation type="unfinished">Firmas: firmar o verificar un mensaje</translation> </message> <message> <source>&Sign Message</source> @@ -3007,23 +3314,23 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <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">La dirección Bitcoin con la que se firmó el mensaje</translation> + <translation type="unfinished">La dirección de Bitcoin con la que se firmará el mensaje</translation> </message> <message> <source>Choose previously used address</source> - <translation type="unfinished">Escoger dirección previamente usada</translation> + <translation type="unfinished">Seleccionar dirección usada anteriormente</translation> </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">Pegar dirección desde portapapeles</translation> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> <message> <source>Enter the message you want to sign here</source> - <translation type="unfinished">Introduzca el mensaje que desea firmar aquÃ</translation> + <translation type="unfinished">Ingresar aquà el mensaje que deseas firmar</translation> </message> <message> <source>Signature</source> @@ -3035,7 +3342,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Firmar el mensaje para demostrar que se posee esta dirección Bitcoin</translation> + <translation type="unfinished">Firmar el mensaje para demostrar que esta dirección de Bitcoin te pertenece</translation> </message> <message> <source>Sign &Message</source> @@ -3043,19 +3350,23 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Reset all sign message fields</source> - <translation type="unfinished">Limpiar todos los campos de la firma de mensaje</translation> + <translation type="unfinished">Restablecer todos los campos de firma de mensaje</translation> </message> <message> <source>Clear &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>&Verify Message</source> <translation type="unfinished">&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">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> + <translation type="unfinished">La dirección de Bitcoin con la que se firmó el mensaje</translation> </message> <message> <source>The signed message to verify</source> @@ -3063,11 +3374,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The signature given when the message was signed</source> - <translation type="unfinished">La firma proporcionada cuando el mensaje fue firmado</translation> + <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">Verificar el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation> + <translation type="unfinished">Verifica el mensaje para asegurarte de que se firmó con la dirección de Bitcoin especificada.</translation> </message> <message> <source>Verify &Message</source> @@ -3075,39 +3386,39 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Reset all verify message fields</source> - <translation type="unfinished">Limpiar todos los campos de la verificación de mensaje</translation> + <translation type="unfinished">Restablecer todos los campos de 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> + <translation type="unfinished">Hacer clic en "Firmar mensaje" para generar una firma</translation> </message> <message> <source>The entered address is invalid.</source> - <translation type="unfinished">La dirección introducida es inválida.</translation> + <translation type="unfinished">La dirección ingresada es inválida.</translation> </message> <message> <source>Please check the address and try again.</source> - <translation type="unfinished">Verifique la dirección e inténtelo de nuevo.</translation> + <translation type="unfinished">Revisa la dirección e intenta de nuevo.</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> + <translation type="unfinished">La dirección ingresada 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> + <translation type="unfinished">Se canceló el desbloqueo de la billetera.</translation> </message> <message> <source>No error</source> - <translation type="unfinished">No hay error</translation> + <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> + <translation type="unfinished">La clave privada para la dirección ingresada no está disponible.</translation> </message> <message> <source>Message signing failed.</source> - <translation type="unfinished">Ha fallado la firma del mensaje.</translation> + <translation type="unfinished">Error al firmar el mensaje.</translation> </message> <message> <source>Message signed.</source> @@ -3115,19 +3426,19 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The signature could not be decoded.</source> - <translation type="unfinished">No se puede decodificar la firma.</translation> + <translation type="unfinished">La firma no pudo decodificarse.</translation> </message> <message> <source>Please check the signature and try again.</source> - <translation type="unfinished">Compruebe la firma e inténtelo de nuevo.</translation> + <translation type="unfinished">Comprueba la firma e intenta 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> + <translation type="unfinished">La firma no coincide con la sÃntesis del mensaje.</translation> </message> <message> <source>Message verification failed.</source> - <translation type="unfinished">La verificación del mensaje ha fallado.</translation> + <translation type="unfinished">Falló la verificación del mensaje.</translation> </message> <message> <source>Message verified.</source> @@ -3138,16 +3449,21 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SplashScreen</name> <message> <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(presiona q para apagar y seguir luego)</translation> + <translation type="unfinished">(Presionar q para apagar y seguir luego)</translation> </message> <message> <source>press q to shutdown</source> - <translation type="unfinished">presiona q para apagar </translation> + <translation type="unfinished">Presionar 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 una transacción con %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 el pool de memoria</translation> @@ -3165,7 +3481,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">%1/sin confirmar</translation> </message> <message> <source>%1 confirmations</source> @@ -3198,13 +3514,17 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>own address</source> <translation type="unfinished">dirección propia</translation> </message> <message> + <source>watch-only</source> + <translation type="unfinished">Solo de observación</translation> + </message> + <message> <source>label</source> <translation type="unfinished">etiqueta</translation> </message> @@ -3229,7 +3549,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Total debit</source> - <translation type="unfinished">Total enviado</translation> + <translation type="unfinished">Débito total</translation> + </message> + <message> + <source>Total credit</source> + <translation type="unfinished">Crédito total</translation> </message> <message> <source>Transaction fee</source> @@ -3237,7 +3561,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Net amount</source> - <translation type="unfinished">Cantidad neta</translation> + <translation type="unfinished">Importe neto</translation> </message> <message> <source>Message</source> @@ -3249,11 +3573,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Transaction ID</source> - <translation type="unfinished">ID</translation> + <translation type="unfinished">Identificador de transacción</translation> </message> <message> <source>Transaction total size</source> - <translation type="unfinished">Tamaño total transacción</translation> + <translation type="unfinished">Tamaño total de transacción</translation> </message> <message> <source>Transaction virtual size</source> @@ -3261,7 +3585,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Output index</source> - <translation type="unfinished">Indice de salida</translation> + <translation type="unfinished">Ãndice de salida</translation> </message> <message> <source>%1 (Certificate was not verified)</source> @@ -3269,11 +3593,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Merchant</source> - <translation type="unfinished">Vendedor</translation> + <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 meterse 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 pocos segundos del tuyo.</translation> + <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> @@ -3285,11 +3609,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Inputs</source> - <translation type="unfinished">entradas</translation> + <translation type="unfinished">Entradas</translation> </message> <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>true</source> @@ -3304,9 +3628,13 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">En este panel se muestra una descripción detallada de la transacción</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation type="unfinished">Detalles para %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> @@ -3319,43 +3647,59 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Label</source> - <translation type="unfinished">Nombre</translation> + <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">Confirmado (%1 confirmaciones)</translation> + <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> + <translation type="unfinished">Inmadura (%1 confirmaciones; estará disponibles después de %2)</translation> </message> <message> <source>Generated but not accepted</source> - <translation type="unfinished">Generado pero no aceptado</translation> + <translation type="unfinished">Generada pero no aceptada</translation> </message> <message> <source>Received with</source> - <translation type="unfinished">Recibido con</translation> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Received from</source> - <translation type="unfinished">Recibidos de</translation> + <translation type="unfinished">Recibida de</translation> </message> <message> <source>Sent to</source> - <translation type="unfinished">Enviado a</translation> + <translation type="unfinished">Enviada a</translation> </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> + </message> + <message> + <source>watch-only</source> + <translation type="unfinished">Solo de observación</translation> </message> <message> <source>(n/a)</source> - <translation type="unfinished">(nd)</translation> + <translation type="unfinished">(n/d)</translation> </message> <message> <source>(no label)</source> @@ -3363,11 +3707,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <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> + <translation type="unfinished">Estado de la transacción. Pasa el mouse 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 en que se recibió la transacción.</translation> + <translation type="unfinished">Fecha y hora en las que se recibió la transacción.</translation> </message> <message> <source>Type of transaction.</source> @@ -3375,7 +3719,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Si una dirección solo de observación está involucrada en esta transacción o no.</translation> </message> <message> <source>User-defined intent/purpose of the transaction.</source> @@ -3383,7 +3727,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Amount removed from or added to balance.</source> - <translation type="unfinished">Cantidad retirada o añadida al saldo.</translation> + <translation type="unfinished">Importe restado del saldo o sumado a este.</translation> </message> </context> <context> @@ -3414,15 +3758,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Received with</source> - <translation type="unfinished">Recibido con</translation> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Sent to</source> - <translation type="unfinished">Enviado a</translation> + <translation type="unfinished">Enviada a</translation> </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> </message> <message> <source>Other</source> @@ -3430,11 +3774,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Ingresar 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> + <translation type="unfinished">Importe mÃnimo</translation> </message> <message> <source>Range…</source> @@ -3454,11 +3798,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy transaction &ID</source> - <translation type="unfinished">Copiar &ID de transacción</translation> + <translation type="unfinished">Copiar &identificador de transacción</translation> </message> <message> <source>Copy &raw transaction</source> - <translation type="unfinished">Copiar transacción &raw</translation> + <translation type="unfinished">Copiar transacción &sin procesar</translation> </message> <message> <source>Copy full transaction &details</source> @@ -3496,7 +3840,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmado</translation> + <translation type="unfinished">Confirmada</translation> + </message> + <message> + <source>Watch-only</source> + <translation type="unfinished">Solo de observación</translation> </message> <message> <source>Date</source> @@ -3508,11 +3856,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Label</source> - <translation type="unfinished">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> </message> <message> <source>Address</source> - <translation type="unfinished">Direccion</translation> + <translation type="unfinished">Dirección</translation> + </message> + <message> + <source>ID</source> + <translation type="unfinished">Identificador</translation> </message> <message> <source>Exporting Failed</source> @@ -3520,15 +3872,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <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 la transacción con %1.</translation> + <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 finalizada</translation> + <translation type="unfinished">Exportación correcta</translation> </message> <message> <source>The transaction history was successfully saved to %1.</source> - <translation type="unfinished">La transacción ha sido guardada en %1.</translation> + <translation type="unfinished">El historial de transacciones se guardó correctamente en %1.</translation> </message> <message> <source>Range:</source> @@ -3536,7 +3888,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>to</source> - <translation type="unfinished">para</translation> + <translation type="unfinished">a</translation> </message> </context> <context> @@ -3546,28 +3898,32 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k Go to File > Open Wallet to load a wallet. - OR -</source> <translation type="unfinished">No se cargó ninguna billetera. -Ir a Archivo > Abrir billetera para cargar una. -- OR -</translation> +Ir a "Archivo > Abrir billetera" para cargar una. +- O -</translation> </message> <message> <source>Create a new wallet</source> - <translation type="unfinished">Crear monedero nuevo</translation> + <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> + <translation type="unfinished">No se puede decodificar la TBPF desde el portapapeles (Base64 inválida)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation type="unfinished">Cargar datos de la transacción</translation> </message> <message> <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished">Transacción firmada parcialmente (*.psbt)</translation> + <translation type="unfinished">Transacción parcialmente firmada (*.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> + <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">No se puede decodificar PSBT</translation> + <translation type="unfinished">No se puede decodificar TBPF</translation> </message> </context> <context> @@ -3578,18 +3934,30 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Fee bump error</source> - <translation type="unfinished">Error de incremento de cuota</translation> + <translation type="unfinished">Error de incremento de comisión</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation type="unfinished">Fallo al incrementar 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 cuota?</translation> + <translation type="unfinished">¿Deseas 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: 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> @@ -3603,7 +3971,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>PSBT copied</source> - <translation type="unfinished">PSBT copiada</translation> + <translation type="unfinished">TBPF copiada</translation> </message> <message> <source>Copied to clipboard</source> @@ -3612,7 +3980,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Can't sign transaction.</source> - <translation type="unfinished">No se ha podido firmar la transacción.</translation> + <translation type="unfinished">No se puede firmar la transacción.</translation> </message> <message> <source>Could not commit transaction</source> @@ -3624,7 +3992,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> </context> <context> @@ -3635,11 +4003,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar los datos en la pestaña actual a un archivo</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> <source>Backup Wallet</source> - <translation type="unfinished">Respaldo de monedero</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera</translation> </message> <message> <source>Wallet Data</source> @@ -3648,19 +4016,19 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Backup Failed</source> - <translation type="unfinished">Ha fallado el respaldo</translation> + <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 en %1.</translation> + <translation type="unfinished">Ocurrió un error al intentar guardar los datos de la billetera en %1.</translation> </message> <message> <source>Backup Successful</source> - <translation type="unfinished">Se ha completado con éxito la copia de respaldo</translation> + <translation type="unfinished">Copia de seguridad correcta</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> + <translation type="unfinished">Los datos de la billetera se guardaron correctamente en %1.</translation> </message> <message> <source>Cancel</source> @@ -3675,11 +4043,11 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">%s dañado. Trata de usar la herramienta de la billetera de Bitcoin para rescatar o restaurar una copia de seguridad.</translation> </message> <message> <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> - <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea no válida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Comunique este incidente a %s, indicando cómo obtuvo la instantánea. Se dejó el estado de encadenamiento de la instantánea no válida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> + <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea inválida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Reporta este incidente a %s, indicando cómo obtuviste la instantánea. Se dejó el estado de cadena de la instantánea inválida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> </message> <message> <source>%s request to listen on port %u. This port is considered "bad" 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> @@ -3702,28 +4070,32 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Es posible que el espacio en disco %s no tenga capacidad para los archivos de bloque. Aproximadamente %u GB de datos se almacenarán en este directorio.</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; ver el archivo adjunto %s o %s.</translation> + </message> + <message> <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">Error al cargar la billetera. Esta requiere que se descarguen bloques, y el software actualmente no admite la carga de billeteras mientras los bloques se descargan fuera de orden, cuando se usan instantáneas de assumeutxo. La billetera deberÃa poder cargarse correctamente después de que la sincronización del nodo alcance la altura %s.</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> + <translation type="unfinished">¡Error al leer %s! Es probable que falten los datos de la transacción o que sean incorrectos. Rescaneando 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> + <translation type="unfinished">Error: El registro del formato del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: El registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: La versión del archivo de 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> + <translation type="unfinished">Error: Las billeteras "legacy" solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32".</translation> </message> <message> <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> @@ -3735,7 +4107,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El archivo peers.dat (%s) es inválido o está dañado. 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>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> @@ -3762,8 +4134,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation type="unfinished">La poda se configuró por debajo del mÃnimo de %d MiB. Usa un valor más alto.</translation> + </message> + <message> <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> - <translation type="unfinished">El modo de poda no es compatible con -reindex-chainstate. Usa en su lugar un -reindex completo.</translation> + <translation type="unfinished">El modo de poda es incompatible con -reindex-chainstate. Usa en su lugar un -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> @@ -3771,7 +4147,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>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.</source> - <translation type="unfinished">Error de renombrado de «%s» → «%s». DeberÃa resolver esto manualmente moviendo o borrando el directorio %s de la instantánea no válida, en otro caso encontrará el mismo error de nuevo en el arranque siguiente.</translation> + <translation type="unfinished">Error al cambiar el nombre de "%s" a "%s". Para resolverlo, mueve o elimina manualmente el directorio %s de la instantánea no válida. De lo contrario, encontrarás el mismo error de nuevo en el siguiente inicio.</translation> </message> <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> @@ -3783,7 +4159,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El importe de la transacción es demasiado pequeño para enviarlo después de deducir 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> @@ -3791,7 +4167,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">Esta es una compilación preliminar de prueba. Úsala bajo tu propia responsabilidad. No la uses para aplicaciones 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> @@ -3799,15 +4175,15 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">Esta es la comisión de transacción que puedes descartar si el cambio es más pequeño que el remanente en este nivel.</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">Impuesto por transacción que pagarás cuando la estimación de impuesto no esté disponible.</translation> + <translation type="unfinished">Esta es la comisión de transacción que puedes pagar cuando los cálculos de comisiones no estén disponibles.</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> + <translation type="unfinished">La longitud total de la cadena de versión de red ( %i) supera la longitud máxima (%i). Reduce 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> @@ -3819,7 +4195,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <translation type="unfinished">Nivel de boletÃn del acceso especificado en categorÃa no mantenida en %1$s=%2$s. Se esperaba %1$s=1:2. CategorÃas válidas: %3$s. Niveles de boletÃn válidos: %4 $s.</translation> + <translation type="unfinished">El nivel de registro de la categorÃa especÃfica no es compatible: %1$s=%2$s. Se esperaba %1$s=<category>:<loglevel>. CategorÃas válidas: %3$s. Niveles de registro válidos: %4 $s.</translation> </message> <message> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> @@ -3831,11 +4207,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> - <translation type="unfinished">Monedero correctamente cargado. El tipo de billetero heredado está siendo obsoleto y mantenimiento para creación de monederos heredados serán eliminados en el futuro. Los monederos heredados pueden ser migrados a un descriptor de monedero con migratewallet.</translation> + <translation type="unfinished">La billetera se creó correctamente. El tipo de billetera "legacy" se está descontinuando, por lo que la asistencia para crear y abrir estas billeteras se eliminará en el futuro. Las billeteras "legacy" se pueden migrar a una billetera basada en descriptores con "migratewallet".</translation> </message> <message> <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <translation type="unfinished">Advertencia: el formato de la billetera del archivo de volcado "%s" no coincide con el formato especificado en la lÃnea de comandos "%s".</translation> + <translation type="unfinished">Advertencia: El formato de la billetera 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> @@ -3843,7 +4219,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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">Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! PodrÃa necesitar una actualización, u otros nodos podrÃan necesitarla.</translation> + <translation type="unfinished">Advertencia: Al parecer no estamos completamente de acuerdo con nuestros pares. Es posible que tengas que realizar una actualización, o que los demás nodos tengan que hacerlo.</translation> </message> <message> <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> @@ -3855,7 +4231,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>%s is set very high!</source> - <translation type="unfinished">¡%s esta configurado muy alto!</translation> + <translation type="unfinished">¡El valor de %s es muy alto!</translation> </message> <message> <source>-maxmempool must be at least %d MB</source> @@ -3867,7 +4243,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">No se puede resolver -%s direccion: '%s'</translation> + <translation type="unfinished">No se puede resolver la dirección de -%s: "%s"</translation> </message> <message> <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> @@ -3883,7 +4259,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> - <translation type="unfinished">La configuración de %s es demasiado alta. Las comisiones tan grandes se podrÃan pagar en una sola transacción.</translation> + <translation type="unfinished">El valor establecido para %s es demasiado alto. Las comisiones tan grandes se podrÃan pagar en una sola transacción.</translation> </message> <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> @@ -3895,7 +4271,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> - <translation type="unfinished">Error leyendo %s. Todas las teclas leÃdas correctamente, pero los datos de transacción o metadatos de dirección puedan ser ausentes o incorrectos.</translation> + <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 metadatos de direcciones, o bien que sean incorrectos.</translation> </message> <message> <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> @@ -3947,11 +4323,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> - <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar una cantidad menor o consolidar manualmente las UTXO de la billetera.</translation> + <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</translation> </message> <message> <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">La cantidad total de monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> + <translation type="unfinished">El monto total de las monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> </message> <message> <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> @@ -3963,14 +4339,14 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> - <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará el pool de memoria.</translation> + <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará la mempool.</translation> </message> <message> <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">Se encontró una entrada heredada inesperada en la billetera del descriptor. Cargando billetera%s + <translation type="unfinished">Se encontró una entrada inesperada tipo "legacy" en la billetera basada en descriptores. Cargando billetera%s Es posible que la billetera haya sido manipulada o creada con malas intenciones. </translation> @@ -4004,8 +4380,16 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Se interrumpió la verificación de bloques</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation type="unfinished">La configuración para %s solo se aplica en la red %s cuando se encuentra en la sección [%s].</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation type="unfinished">Derechos de autor (C) %i-%i</translation> + </message> + <message> <source>Corrupted block database detected</source> - <translation type="unfinished">Corrupción de base de datos de bloques detectada.</translation> + <translation type="unfinished">Se detectó que la base de datos de bloques está dañada.</translation> </message> <message> <source>Could not find asmap file %s</source> @@ -4025,7 +4409,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Done loading</source> - <translation type="unfinished">Carga lista</translation> + <translation type="unfinished">Carga completa</translation> </message> <message> <source>Dump file %s does not exist.</source> @@ -4045,7 +4429,11 @@ No se puede restaurar la copia de seguridad de la billetera.</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> + <translation type="unfinished">Error al inicializar el entorno de la base de datos de la billetera %s.</translation> + </message> + <message> + <source>Error loading %s</source> + <translation type="unfinished">Error al cargar %s</translation> </message> <message> <source>Error loading %s: Private keys can only be disabled during creation</source> @@ -4053,19 +4441,19 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error loading %s: Wallet corrupted</source> - <translation type="unfinished">Error cargando %s: Monedero corrupto</translation> + <translation type="unfinished">Error al cargar %s: billetera dañada</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> + <translation type="unfinished">Error al cargar %s: la billetera requiere una versión más reciente de %s</translation> </message> <message> <source>Error loading block database</source> - <translation type="unfinished">Error cargando base de datos de bloques</translation> + <translation type="unfinished">Error al cargar la 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> + <translation type="unfinished">Error al abrir la base de datos de bloques</translation> </message> <message> <source>Error reading configuration file: %s</source> @@ -4085,7 +4473,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">Error: no se puede extraer el destino del scriptpubkey generado</translation> + <translation type="unfinished">Error: No se puede extraer el destino del scriptpubkey generado</translation> </message> <message> <source>Error: Couldn't create cursor into database</source> @@ -4105,11 +4493,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió una clave que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió una clave que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió un valor que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió un valor que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> @@ -4129,15 +4517,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: This wallet is already a descriptor wallet</source> - <translation type="unfinished">Error: Esta billetera ya es de descriptores</translation> + <translation type="unfinished">Error: Esta billetera ya está basada en descriptores</translation> </message> <message> <source>Error: Unable to begin reading all records in the database</source> - <translation type="unfinished">Error: No se puede comenzar a leer todos los registros en la base de datos</translation> + <translation type="unfinished">Error: No se pueden 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 se puede realizar una copia de seguridad de tu billetera</translation> + <translation type="unfinished">Error: No se puede realizar una copia de seguridad de la billetera</translation> </message> <message> <source>Error: Unable to parse version %u as a uint32_t</source> @@ -4149,7 +4537,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Error: no es capaz de leer el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo leer el registro del mejor localizador de bloques de la billetera.</translation> </message> <message> <source>Error: Unable to remove watchonly address book data</source> @@ -4161,16 +4549,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solucionable.</translation> </message> <message> <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor monedero vigilado del bloque del registro localizador</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solo de observación.</translation> </message> <message> <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera 1%s - </translation> + <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera %s</translation> </message> <message> <source>Error: database transaction cannot be executed for wallet %s</source> @@ -4178,7 +4565,7 @@ No se puede restaurar la copia de seguridad de la billetera.</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. Use -listen=0 si desea esto.</translation> + <translation type="unfinished">Fallo al escuchar en todos los puertos. Usa -listen=0 si quieres hacerlo.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> @@ -4186,7 +4573,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Es erróneo al iniciar indizados, se apaga...</translation> + <translation type="unfinished">Error al iniciar Ãndices, cerrando...</translation> </message> <message> <source>Failed to verify database</source> @@ -4194,7 +4581,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failure removing transaction: %s</source> - <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> + <translation type="unfinished">Error al eliminar la transacción: %s</translation> </message> <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> @@ -4210,15 +4597,19 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">Incorrecto o bloque de génesis no encontrado. Datadir equivocada para la red?</translation> + <translation type="unfinished">El bloque génesis es incorrecto o no se encontró. ¿El directorio de datos es equivocado para la red?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation type="unfinished">Fallo al inicializar la comprobación de estado. %s se cerrará.</translation> </message> <message> <source>Input not found or already spent</source> - <translation type="unfinished">No se encontró o ya se gastó la entrada</translation> + <translation type="unfinished">La entrada no se encontró o ya se gastó</translation> </message> <message> <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">dbcache insuficiente para la verificación de bloques</translation> + <translation type="unfinished">Dbcache insuficiente para la verificación de bloques</translation> </message> <message> <source>Insufficient funds</source> @@ -4226,15 +4617,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">La dirección -i2psam o el nombre de host no es válido: "%s" </translation> + <translation type="unfinished">Dirección o nombre de host de -i2psam inválido: "%s" </translation> </message> <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -onion o dominio '%s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -onion inválido: "%s"</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -proxy o dominio ' %s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -proxy inválido: "%s"</translation> </message> <message> <source>Invalid P2P permission: '%s'</source> @@ -4249,16 +4640,24 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Importe inválido para %s=<amount>: "%s"</translation> </message> <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation type="unfinished">Importe inválido para -%s=<amount>: "%s"</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation type="unfinished">Máscara de red inválida especificada en -whitelist: "%s"</translation> + </message> + <message> <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Puerto no válido especificado en%s: '%s'</translation> + <translation type="unfinished">Puerto no válido especificado en %s: "%s"</translation> </message> <message> <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no válida %s</translation> + <translation type="unfinished">La entrada preseleccionada no es válida %s</translation> </message> <message> <source>Listening for incoming connections failed (listen returned error %s)</source> - <translation type="unfinished">Fallo en la escucha para conexiones entrantes (la escucha devolvió el error %s)</translation> + <translation type="unfinished">Fallo al escuchar conexiones entrantes (la escucha devolvió el error %s)</translation> </message> <message> <source>Loading P2P addresses…</source> @@ -4266,7 +4665,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Loading banlist…</source> - <translation type="unfinished">Cargando lista de bloqueos...</translation> + <translation type="unfinished">Cargando lista de prohibiciones...</translation> </message> <message> <source>Loading block index…</source> @@ -4278,27 +4677,31 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Missing amount</source> - <translation type="unfinished">Falta la cantidad</translation> + <translation type="unfinished">Falta el importe</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 la transacción</translation> </message> <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation type="unfinished">Se necesita especificar un puerto con -whitebind: "%s"</translation> + </message> + <message> <source>No addresses available</source> <translation type="unfinished">No hay direcciones disponibles</translation> </message> <message> <source>Not enough file descriptors available.</source> - <translation type="unfinished">No hay suficientes descriptores de archivo disponibles. </translation> + <translation type="unfinished">No hay suficientes descriptores de archivo disponibles.</translation> </message> <message> <source>Not found pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no encontrada%s</translation> + <translation type="unfinished">La entrada preseleccionada no se encontró %s</translation> </message> <message> <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no solucionable %s</translation> + <translation type="unfinished">La entrada preseleccionada no se puede solucionar %s</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -4310,7 +4713,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Pruning blockstore…</source> - <translation type="unfinished">Podando almacén de bloques…</translation> + <translation type="unfinished">Podando almacenamiento 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> @@ -4342,7 +4749,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished">Transacción falló</translation> + <translation type="unfinished">Fallo al firmar la transacción</translation> </message> <message> <source>Specified -walletdir "%s" does not exist</source> @@ -4370,7 +4777,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The source code is available from %s.</source> - <translation type="unfinished">El código fuente esta disponible desde %s.</translation> + <translation type="unfinished">El código fuente está disponible en %s.</translation> </message> <message> <source>The specified config file %s does not exist</source> @@ -4378,15 +4785,23 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">El monto de la transacción es demasiado pequeño para pagar la comisión</translation> + <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">La billetera evitará pagar menos que 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 tarifa mÃnima a pagar en cada transacción.</translation> + <translation type="unfinished">Esta es la comisión mÃnima de transacción que pagas 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 tarifa a pagar si realizas una transacción.</translation> + <translation type="unfinished">Esta es la comisión de transacción que pagarás si envÃas una transacción.</translation> </message> <message> <source>Transaction %s does not belong to this wallet</source> @@ -4394,11 +4809,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished">Transacción muy pequeña</translation> + <translation type="unfinished">El importe de la transacción es demasiado pequeño</translation> </message> <message> <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Los montos de la transacción no debe ser negativo</translation> + <translation type="unfinished">Los importes de la transacción no pueden ser negativos</translation> </message> <message> <source>Transaction change output index out of range</source> @@ -4406,7 +4821,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction must have at least one recipient</source> - <translation type="unfinished">La transacción debe tener al menos un destinatario</translation> + <translation type="unfinished">La transacción debe incluir al menos un destinatario</translation> </message> <message> <source>Transaction needs a change address, but we can't generate it.</source> @@ -4414,7 +4829,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction too large</source> - <translation type="unfinished">Transacción muy grande</translation> + <translation type="unfinished">Transacción demasiado grande</translation> </message> <message> <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> @@ -4453,6 +4868,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">No se puede analizar -maxuploadtarget: "%s"</translation> </message> <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation type="unfinished">No se puede iniciar el servidor HTTP. Consulta el registro de depuración para obtener información.</translation> + </message> + <message> <source>Unable to unload the wallet before migrating</source> <translation type="unfinished">No se puede descargar la billetera antes de la migración</translation> </message> @@ -4470,7 +4889,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">La red especificada en -onlynet '%s' es desconocida</translation> + <translation type="unfinished">Se desconoce la red especificada en -onlynet: "%s"</translation> </message> <message> <source>Unknown new rules activated (versionbit %i)</source> @@ -4478,15 +4897,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Nivel de acceso global %s = %s no mantenido. Los valores válidos son: %s.</translation> + <translation type="unfinished">El nivel de registro global %s=%s no es compatible. Valores válidos: %s.</translation> </message> <message> <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Creación errónea del fichero monedero: %s</translation> + <translation type="unfinished">Error al crear el archivo de la billetera: %s</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates no está mantenido en el encadenamiento %s.</translation> + <translation type="unfinished">acceptstalefeeestimates no se admite en la cadena %s.</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> @@ -4494,11 +4913,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Error: no pudo agregar tx de solo vigÃa %s para monedero de solo vigÃa</translation> + <translation type="unfinished">Error: No se pudo agregar la transacción %s a la billetera solo de observación.</translation> </message> <message> <source>Error: Could not delete watchonly transactions. </source> - <translation type="unfinished">Error: no se pudieron eliminar las transacciones de watchonly.</translation> + <translation type="unfinished">Error: No se pudieron eliminar las transacciones solo de observación</translation> </message> <message> <source>User Agent comment (%s) contains unsafe characters.</source> diff --git a/src/qt/locale/bitcoin_es_SV.ts b/src/qt/locale/bitcoin_es_SV.ts index 2edd75a5da..82e4242654 100644 --- a/src/qt/locale/bitcoin_es_SV.ts +++ b/src/qt/locale/bitcoin_es_SV.ts @@ -11,11 +11,11 @@ </message> <message> <source>&New</source> - <translation type="unfinished">Es Nuevo</translation> + <translation type="unfinished">&Nueva</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copia la dirección actualmente seleccionada al portapapeles del sistema</translation> + <translation type="unfinished">Copiar la dirección seleccionada actualmente al portapapeles del sistema</translation> </message> <message> <source>&Copy</source> @@ -27,41 +27,45 @@ </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 la dirección seleccionada de la lista</translation> </message> <message> <source>Enter address or label to search</source> - <translation type="unfinished">Introduce una dirección o etiqueta para buscar</translation> + <translation type="unfinished">Ingresar una dirección o etiqueta para buscar</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar a un archivo los datos de esta pestaña</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> + </message> + <message> + <source>&Export</source> + <translation type="unfinished">&Exportar</translation> </message> <message> <source>&Delete</source> - <translation type="unfinished">&Eliminar</translation> + <translation type="unfinished">&Borrar</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished">Escoja la dirección a la que se enviarán monedas</translation> + <translation type="unfinished">Elige la dirección a la que se enviarán monedas</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished">Escoja la dirección donde quiere recibir monedas</translation> + <translation type="unfinished">Elige la dirección con la que se recibirán monedas</translation> </message> <message> <source>C&hoose</source> - <translation type="unfinished">&Escoger</translation> + <translation type="unfinished">&Seleccionar</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">Estas son sus direcciones Bitcoin para enviar pagos. Compruebe siempre la cantidad y la dirección de recibo antes de transferir monedas.</translation> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para enviar pagos. Revisa siempre el importe 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 sus direcciones de Bitcoin para recibir los pagos. -Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir para crear una nueva direccion. Firmar es posible solo con la direccion del tipo "legado"</translation> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para recibir pagos. Usa el botón "Crear nueva dirección de recepción" en la pestaña "Recibir" para crear nuevas direcciones. +Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>&Copy Address</source> @@ -69,7 +73,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Copy &Label</source> - <translation type="unfinished">Copiar y etiquetar</translation> + <translation type="unfinished">Copiar &etiqueta</translation> </message> <message> <source>&Edit</source> @@ -77,7 +81,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Export Address List</source> - <translation type="unfinished">Exportar la Lista de Direcciones</translation> + <translation type="unfinished">Exportar lista de direcciones</translation> </message> <message> <source>Comma separated file</source> @@ -85,9 +89,17 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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">Ocurrió un error al intentar guardar la lista de direcciones en %1. Inténtalo de nuevo.</translation> + </message> + <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">Direcciones de envÃo - %1</translation> + </message> + <message> <source>Receiving addresses - %1</source> - <translation type="unfinished">Recepción de direcciones - %1 -</translation> + <translation type="unfinished">Direcciones de recepción - %1</translation> </message> <message> <source>Exporting Failed</source> @@ -98,7 +110,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <name>AddressTableModel</name> <message> <source>Label</source> - <translation type="unfinished">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> </message> <message> <source>Address</source> @@ -112,36 +124,44 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <context> <name>AskPassphraseDialog</name> <message> + <source>Passphrase Dialog</source> + <translation type="unfinished">Diálogo de frase de contraseña</translation> + </message> + <message> <source>Enter passphrase</source> - <translation type="unfinished">Introduce contraseña actual</translation> + <translation type="unfinished">Ingresar la frase de contraseña</translation> </message> <message> <source>New passphrase</source> - <translation type="unfinished">Nueva contraseña</translation> + <translation type="unfinished">Nueva frase de contraseña</translation> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Repita la nueva contraseña</translation> + <translation type="unfinished">Repetir la nueva frase de contraseña</translation> </message> <message> <source>Show passphrase</source> - <translation type="unfinished">Mostrar contraseña</translation> + <translation type="unfinished">Mostrar la frase de contraseña</translation> </message> <message> <source>Encrypt wallet</source> - <translation type="unfinished">Encriptar la billetera</translation> + <translation type="unfinished">Encriptar billetera</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Esta operación necesita su contraseña de billetera para desbloquearla.</translation> + <translation type="unfinished">Esta operación requiere la frase de contraseña de la billetera para desbloquearla.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation type="unfinished">Desbloquear billetera</translation> </message> <message> <source>Change passphrase</source> - <translation type="unfinished">Cambia contraseña</translation> + <translation type="unfinished">Cambiar frase de contraseña</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation type="unfinished">Confirma el cifrado de este monedero</translation> + <translation type="unfinished">Confirmar el encriptado de la billetera</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> @@ -149,55 +169,59 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">¿Esta seguro que quieres cifrar tu monedero?</translation> + <translation type="unfinished">¿Seguro quieres encriptar la billetera?</translation> </message> <message> <source>Wallet encrypted</source> - <translation type="unfinished">Billetera codificada</translation> + <translation type="unfinished">Billetera encriptada</translation> </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation type="unfinished">Introduce la contraseña nueva para la billetera. <br/>Por favor utiliza una contraseña de <b>diez o más caracteres aleatorios</b>, u <b>ocho o más palabras</b>.</translation> + <translation type="unfinished">Ingresa la nueva frase de contraseña para la billetera. <br/>Usa una frase de contraseña de <b>diez o más caracteres aleatorios</b>, u <b>ocho o más palabras</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation type="unfinished">Introduce la contraseña antigua y la nueva para el monedero.</translation> + <translation type="unfinished">Ingresa la antigua frase de contraseña 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 garantiza total protección de robo de tus bitcoins si tu ordenador es infectado con malware.</translation> + <translation type="unfinished">Recuerda que encriptar tu billetera no garantiza la protección total contra el robo de tus bitcoins si la computadora está infectada con malware.</translation> </message> <message> <source>Wallet to be encrypted</source> - <translation type="unfinished">Billetera para cifrar</translation> + <translation type="unfinished">Billetera para encriptar</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> - <translation type="unfinished">Tu billetera esta por ser encriptada</translation> + <translation type="unfinished">Tu billetera está a punto de encriptarse.</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Tu monedero está ahora cifrado</translation> + <translation type="unfinished">Tu billetera ahora está encriptada.</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 respaldo anterior que hayas hecho del archivo de tu billetera debe ser reemplazado por el nuevo archivo encriptado que has generado. Por razones de seguridad, todos los respaldos realizados anteriormente serán inutilizables al momento de que utilices tu nueva billetera encriptada.</translation> + <translation type="unfinished">IMPORTANTE: Cualquier copia de seguridad anterior que hayas hecho del archivo de la billetera se deberá reemplazar por el nuevo archivo encriptado que generaste. Por motivos de seguridad, las copias de seguridad realizadas anteriormente quedarán obsoletas en cuanto empieces a usar la nueva billetera encriptada.</translation> </message> <message> <source>Wallet encryption failed</source> - <translation type="unfinished">Ha fallado el cifrado del monedero</translation> + <translation type="unfinished">Falló el encriptado de la billetera</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">La encriptación de la billetera falló debido a un error interno. La billetera no se encriptó.</translation> + <translation type="unfinished">El encriptado de la billetera falló debido a un error interno. La billetera no se encriptó.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation type="unfinished">Las frases de contraseña proporcionadas no coinciden.</translation> </message> <message> <source>Wallet unlock failed</source> - <translation type="unfinished">Ha fallado el desbloqueo del monedero</translation> + <translation type="unfinished">Falló el desbloqueo de la billetera</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">La frase de contraseña ingresada para el descifrado de la billetera fue incorrecta.</translation> + <translation type="unfinished">La frase de contraseña introducida para el cifrado de la billetera es incorrecta.</translation> </message> <message> <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> @@ -205,7 +229,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">La contraseña de la billetera ha sido cambiada.</translation> + <translation type="unfinished">La frase de contraseña de la billetera se cambió correctamente.</translation> </message> <message> <source>Passphrase change failed</source> @@ -215,12 +239,20 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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">La frase de contraseña que se ingresó para descifrar la billetera es incorrecta. Contiene un carácter nulo (es decir, un byte cero). Si la frase de contraseña se configuró con una versión de este software anterior a la 25.0, vuelve a intentarlo solo con los caracteres hasta el primer carácter nulo, pero sin incluirlo.</translation> </message> - </context> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation type="unfinished">Advertencia: ¡Las mayúsculas están activadas!</translation> + </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">Bloqueado hasta</translation> + <translation type="unfinished">Prohibido hasta</translation> </message> </context> <context> @@ -230,8 +262,12 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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 ha producido un error garrafal. %1Ya no podrá continuar de manera segura y abandonará.</translation> + <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> @@ -239,7 +275,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </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">Un error interno ocurrió. %1 intentará continuar. Este es un error inesperado que puede ser reportado de las formas que se muestran debajo,</translation> + <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> @@ -252,11 +288,19 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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 ejecutar de nuevo el programa con -nosettings</translation> + <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>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 todavÃa no ha terminado de forma segura...</translation> + <translation type="unfinished">%1 aún no salió de forma segura...</translation> + </message> + <message> + <source>unknown</source> + <translation type="unfinished">desconocido</translation> + </message> + <message> + <source>Embedded "%1"</source> + <translation type="unfinished">"%1" integrado</translation> </message> <message> <source>Default system font "%1"</source> @@ -268,11 +312,11 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation type="unfinished">Ingresa una dirección de Bitcoin (Ejemplo: %1)</translation> + <translation type="unfinished">Ingresar una dirección de Bitcoin (por ejemplo, %1)</translation> </message> <message> <source>Unroutable</source> @@ -286,7 +330,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <message> <source>Outbound</source> <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> <message> <source>Full Relay</source> @@ -296,12 +340,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <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>Feeler</source> - <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> - <translation type="unfinished">Sensor</translation> + <translation type="unfinished">Retransmisión de bloques</translation> </message> <message> <source>Address Fetch</source> @@ -309,10 +348,6 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">Recuperación de dirección</translation> </message> <message> - <source>%1 h</source> - <translation type="unfinished">%1 d</translation> - </message> - <message> <source>None</source> <translation type="unfinished">Ninguno</translation> </message> @@ -362,7 +397,7 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform>%n años</numerusform> + <numerusform>%n año</numerusform> <numerusform>%n años</numerusform> </translation> </message> @@ -370,20 +405,81 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <context> <name>BitcoinGUI</name> <message> + <source>&Overview</source> + <translation type="unfinished">&Vista general</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation type="unfinished">Muestra una vista general de la billetera</translation> + </message> + <message> + <source>&Transactions</source> + <translation type="unfinished">&Transacciones</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation type="unfinished">Explora el historial de transacciones</translation> + </message> + <message> + <source>E&xit</source> + <translation type="unfinished">&Salir</translation> + </message> + <message> + <source>Quit application</source> + <translation type="unfinished">Salir del programa</translation> + </message> + <message> + <source>&About %1</source> + <translation type="unfinished">&Acerca de %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation type="unfinished">Mostrar Información sobre %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation type="unfinished">Acerca de &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation type="unfinished">Mostrar información sobre Qt</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation type="unfinished">Modificar las opciones de configuración para %1</translation> + </message> + <message> <source>Create a new wallet</source> - <translation type="unfinished">Crear monedero nuevo</translation> + <translation type="unfinished">Crear una nueva billetera</translation> </message> <message> <source>&Minimize</source> <translation type="unfinished">&Minimizar</translation> </message> <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> + <source>Network activity disabled.</source> + <extracomment>A substring of the tooltip.</extracomment> + <translation type="unfinished">Actividad de red deshabilitada.</translation> + </message> + <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation type="unfinished">Proxy <b>habilitado</b>: %1</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation type="unfinished">Enviar monedas a una dirección de Bitcoin</translation> + </message> + <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Respaldar monedero en otra ubicación</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera 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> + <translation type="unfinished">Cambiar la frase de contraseña utilizada para encriptar la billetera</translation> </message> <message> <source>&Send</source> @@ -394,28 +490,44 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">&Recibir</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Opciones…</translation> + </message> + <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&Cifrar monedero</translation> + <translation type="unfinished">&Encriptar billetera…</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> + <translation type="unfinished">Encriptar las claves privadas que pertenecen a la billetera</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Realizar copia de seguridad de la billetera...</translation> </message> <message> <source>&Change Passphrase…</source> <translation type="unfinished">&Cambiar frase de contraseña...</translation> </message> <message> + <source>Sign &message…</source> + <translation type="unfinished">Firmar &mensaje...</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Firmar mensajes con sus direcciones Bitcoin para probar la propiedad</translation> + <translation type="unfinished">Firmar mensajes con tus direcciones de Bitcoin para demostrar que te pertenecen</translation> + </message> + <message> + <source>&Verify message…</source> + <translation type="unfinished">&Verificar mensaje...</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Verificar un mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation> + <translation type="unfinished">Verificar mensajes para asegurarte de que estén firmados con direcciones de Bitcoin concretas</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -423,15 +535,15 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Cerrar monedero...</translation> + <translation type="unfinished">Cerrar billetera...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Crear monedero...</translation> + <translation type="unfinished">Crear billetera...</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Cerrar todos los monederos...</translation> + <translation type="unfinished">Cerrar todas las billeteras...</translation> </message> <message> <source>&File</source> @@ -442,6 +554,10 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p <translation type="unfinished">&Configuración</translation> </message> <message> + <source>&Help</source> + <translation type="unfinished">&Ayuda</translation> + </message> + <message> <source>Tabs toolbar</source> <translation type="unfinished">Barra de pestañas</translation> </message> @@ -467,48 +583,54 @@ Usa el boton "Crear nueva direccion de recibimiento" en la pestaña de recibir p </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished"> -Solicitar pagos (genera códigos QR y bitcoin: URI) - </translation> + <translation type="unfinished">Solicitar pagos (genera códigos QR y URI de tipo "bitcoin:")</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones y etiquetas de envÃo usadas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de envÃo usadas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones y etiquetas de recepción usadas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de recepción usadas</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">opciones de la &Linea de comandos</translation> + <translation type="unfinished">&Opciones de lÃnea de comandos</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>Procesado %n bloque del historial de transacciones.</numerusform> - <numerusform>Procesados %n bloques del historial de transacciones.</numerusform> + <numerusform>Se procesó %n bloque del historial de transacciones.</numerusform> + <numerusform>Se procesaron %n bloques del historial de transacciones.</numerusform> </translation> </message> <message> + <source>%1 behind</source> + <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 se generó hace %1.</translation> + </message> + <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">Las transacciones después de esto todavÃa no serán visibles.</translation> + <translation type="unfinished">Las transacciones posteriores aún no están visibles.</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Aviso</translation> + <translation type="unfinished">Advertencia</translation> </message> <message> <source>Information</source> - <translation type="unfinished">Información </translation> + <translation type="unfinished">Información</translation> </message> <message> <source>Up to date</source> - <translation type="unfinished">Actualizado al dia </translation> + <translation type="unfinished">Actualizado</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction</source> @@ -516,7 +638,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Cargar PSBT desde el &portapapeles...</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> @@ -524,11 +646,11 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Abrir consola de depuración y diagnóstico de nodo</translation> + <translation type="unfinished">Abrir la consola de depuración y diagnóstico del nodo</translation> </message> <message> <source>&Sending addresses</source> @@ -536,15 +658,23 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">&Direcciones de destino</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un URI de tipo "bitcoin:"</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Abrir monedero</translation> + <translation type="unfinished">Abrir billetera</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Abrir una billetera</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar billetera</translation> </message> <message> <source>Restore Wallet…</source> @@ -558,7 +688,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Migrate Wallet</source> @@ -569,20 +699,24 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation type="unfinished">Migrar una billetera</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished">Mostrar el mensaje de ayuda %1 para obtener una lista de las posibles opciones de lÃnea de comandos de Bitcoin</translation> + </message> + <message> <source>&Mask values</source> <translation type="unfinished">&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> + <translation type="unfinished">Ocultar los valores en la pestaña "Vista general"</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> <message> <source>No wallets available</source> - <translation type="unfinished">Monederos no disponibles</translation> + <translation type="unfinished">No hay billeteras disponibles</translation> </message> <message> <source>Wallet Data</source> @@ -602,13 +736,21 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <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> + <translation type="unfinished">Nombre de la billetera</translation> </message> <message> <source>&Window</source> <translation type="unfinished">&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> @@ -618,14 +760,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>S&how</source> - <translation type="unfinished">M&ostrar</translation> + <translation type="unfinished">&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>%n conexiones activas con la red Bitcoin</numerusform> - <numerusform>%n conexiones activas con la red Bitcoin </numerusform> + <numerusform>%n conexión activa con la red de Bitcoin.</numerusform> + <numerusform>%n conexiones activas con la red de Bitcoin.</numerusform> </translation> </message> <message> @@ -658,7 +800,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <translation type="unfinished">No se puede crear una nueva billetera, el software se compiló sin soporte sqlite (requerido para billeteras descriptivas)</translation> + <translation type="unfinished">No se puede crear una billetera nueva, ya que el software se compiló sin compatibilidad con sqlite (requerida para billeteras basadas en descriptores)</translation> </message> <message> <source>Warning: %1</source> @@ -691,7 +833,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <message> <source>Label: %1 </source> - <translation type="unfinished">Etiqueta: %1 + <translation type="unfinished">Etiqueta %1 </translation> </message> <message> @@ -706,7 +848,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Incoming transaction</source> - <translation type="unfinished">Transacción recibida</translation> + <translation type="unfinished">Transacción entrante</translation> </message> <message> <source>HD key generation is <b>enabled</b></source> @@ -714,7 +856,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">La generación de la clave HD está <b> desactivada </ b></translation> + <translation type="unfinished">La generación de clave HD está <b>deshabilitada</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -722,11 +864,11 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">La billetera está <b> encriptada </ b> y actualmente <b> desbloqueada </ b></translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>desbloqueda</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">La billetera está encriptada y bloqueada recientemente</translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>bloqueda</b></translation> </message> <message> <source>Original message:</source> @@ -737,7 +879,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <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 las cantidades. Haga clic para seleccionar otra unidad.</translation> + <translation type="unfinished">Unidad en la que se muestran los importes. Haz clic para seleccionar otra unidad.</translation> </message> </context> <context> @@ -763,20 +905,48 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation type="unfinished">Después de la comisión:</translation> </message> <message> + <source>Change:</source> + <translation type="unfinished">Cambio:</translation> + </message> + <message> + <source>(un)select all</source> + <translation type="unfinished">(des)marcar todos</translation> + </message> + <message> + <source>Tree mode</source> + <translation type="unfinished">Modo árbol</translation> + </message> + <message> + <source>List mode</source> + <translation type="unfinished">Modo lista</translation> + </message> + <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> - <source>Received with address</source> + <source>Received with label</source> <translation type="unfinished">Recibido con etiqueta</translation> </message> <message> + <source>Received with address</source> + <translation type="unfinished">Recibido con dirección</translation> + </message> + <message> + <source>Date</source> + <translation type="unfinished">Fecha</translation> + </message> + <message> + <source>Confirmations</source> + <translation type="unfinished">Confirmaciones</translation> + </message> + <message> <source>Confirmed</source> <translation type="unfinished">Confirmada</translation> </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>&Copy address</source> @@ -796,7 +966,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">B&loquear no gastado</translation> + <translation type="unfinished">&Bloquear importe no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -808,11 +978,19 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Copy fee</source> - <translation type="unfinished">Tarifa de copia</translation> + <translation type="unfinished">Copiar comisión</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de la tarifa</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 change</source> + <translation type="unfinished">Copiar cambio</translation> </message> <message> <source>(%1 locked)</source> @@ -820,7 +998,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation type="unfinished">Puede variar en +/- %1 satoshi(s) por entrada.</translation> + <translation type="unfinished">Puede variar +/- %1 satoshi(s) por entrada.</translation> </message> <message> <source>(no label)</source> @@ -828,12 +1006,21 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">Cambio desde %1 (%2)</translation> + <translation type="unfinished">cambio desde %1 (%2)</translation> </message> - </context> + <message> + <source>(change)</source> + <translation type="unfinished">(cambio)</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">Crear billetera</translation> + </message> + <message> <source>Creating Wallet <b>%1</b>…</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 billetera <b>%1</b>…</translation> @@ -844,7 +1031,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Create wallet warning</source> - <translation type="unfinished">Advertencia de crear billetera</translation> + <translation type="unfinished">Advertencia al crear la billetera</translation> </message> <message> <source>Can't list signers</source> @@ -860,12 +1047,12 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <message> <source>Load Wallets</source> <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment> - <translation type="unfinished">Cargar monederos</translation> + <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 monederos...</translation> + <translation type="unfinished">Cargando billeteras...</translation> </message> </context> <context> @@ -876,7 +1063,7 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </message> <message> <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> - <translation type="unfinished">Estas seguro de wue deseas migrar la billetera 1 %1 1 ?</translation> + <translation type="unfinished">¿Seguro deseas migrar la billetera <i>%1</i>?</translation> </message> <message> <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. @@ -885,10 +1072,10 @@ If this wallet contains any solvable but not watched scripts, a different and ne The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> <translation type="unfinished">La migración de la billetera la convertirá en una o más billeteras basadas en descriptores. Será necesario realizar una nueva copia de seguridad de la billetera. -Si esta billetera contiene scripts solo de lectura, se creará una nueva billetera que los contenga. -Si esta billetera contiene scripts solucionables pero no de lectura, se creará una nueva billetera diferente que los contenga. +Si esta billetera contiene scripts solo de observación, se creará una nueva billetera que los contenga. +Si esta billetera contiene scripts solucionables pero no de observación, se creará una nueva billetera diferente que los contenga. -El proceso de migración creará una copia de seguridad de la billetera antes de migrar. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En el caso de una migración incorrecta, la copia de seguridad puede restaurarse con la funcionalidad "Restore Wallet" (Restaurar billetera).</translation> +El proceso de migración creará una copia de seguridad de la billetera antes de proceder. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En caso de que la migración falle, se puede restaurar la copia de seguridad con la funcionalidad "Restaurar billetera".</translation> </message> <message> <source>Migrate Wallet</source> @@ -904,11 +1091,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Guiones vigilantes han sido migrados a un monedero con el nombre '%1'.</translation> + <translation type="unfinished">Los scripts solo de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Solucionable pero ninguno de los guiones vigilados han sido migrados a un monedero llamados '%1'.</translation> + <translation type="unfinished">Los scripts solucionables pero no de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Migration failed</source> @@ -922,22 +1109,26 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 sobre crear monedero</translation> + <translation type="unfinished">Advertencia al abrir billetera</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</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 billetera</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</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 <b>%1</b>...</translation> + <translation type="unfinished">Abriendo billetera <b>%1</b>...</translation> </message> </context> <context> @@ -945,12 +1136,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Restaurar billetera</translation> </message> <message> <source>Restoring Wallet <b>%1</b>…</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 <b>%1</b>…</translation> + <translation type="unfinished">Restaurando billetera <b>%1</b>…</translation> </message> <message> <source>Restore wallet failed</source> @@ -971,39 +1162,63 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <context> <name>WalletController</name> <message> + <source>Close wallet</source> + <translation type="unfinished">Cerrar billetera</translation> + </message> + <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">¿Estás seguro de que deseas cerrar el monedero <i>%1</i>?</translation> + <translation type="unfinished">¿Seguro deseas cerrar la billetera <i>%1</i>?</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> + <translation type="unfinished">Cerrar la billetera durante demasiado tiempo puede causar la resincronización de toda la cadena si el podado está habilitado.</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">¿Está seguro de que desea cerrar todas las billeteras?</translation> + <translation type="unfinished">¿Seguro quieres cerrar todas las billeteras?</translation> </message> </context> <context> <name>CreateWalletDialog</name> <message> + <source>Create Wallet</source> + <translation type="unfinished">Crear billetera</translation> + </message> + <message> <source>You are one step away from creating your new wallet!</source> <translation type="unfinished">Estás a un paso de crear tu nueva billetera.</translation> </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Escribe un nombre y, si lo deseas, activa las opciones avanzadas.</translation> + <translation type="unfinished">Escribe un nombre y, si quieres, activa las opciones avanzadas.</translation> </message> <message> <source>Wallet Name</source> - <translation type="unfinished">Nombre del monedero</translation> + <translation type="unfinished">Nombre de la billetera </translation> + </message> + <message> + <source>Wallet</source> + <translation type="unfinished">Billetera</translation> </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">Encriptar la billetera. La billetera será encriptada con una contraseña de tu elección.</translation> + <translation type="unfinished">Encriptar la billetera. La billetera se encriptará con una frase de contraseña de tu elección.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation type="unfinished">Encriptar billetera</translation> + </message> + <message> + <source>Advanced Options</source> + <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">Desactivar las claves privadas para esta billetera. Las billeteras con claves privadas desactivadas no tendrán claves privadas y no podrán tener ninguna semilla HD ni claves privadas importadas. Esto es ideal para billeteras solo de observación.</translation> </message> <message> <source>Disable Private Keys</source> @@ -1011,11 +1226,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Crea una billetera en blanco. Las billeteras en blanco inicialmente no tienen llaves privadas ni scripts. Las llaves privadas y las direcciones pueden ser importadas o se puede establecer una semilla HD más tarde.</translation> </message> <message> <source>Make Blank Wallet</source> - <translation type="unfinished">Crear billetera vacÃa</translation> + <translation type="unfinished">Crear billetera en blanco</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">Usa un dispositivo de firma externo, por ejemplo, una billetera de hardware. Configura primero el script del firmante externo en las preferencias de la billetera.</translation> </message> <message> <source>External signer</source> @@ -1028,42 +1247,62 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> </context> <context> <name>EditAddressDialog</name> <message> + <source>Edit Address</source> + <translation type="unfinished">Editar dirección</translation> + </message> + <message> <source>&Label</source> - <translation type="unfinished">Y etiqueta</translation> + <translation type="unfinished">&Etiqueta</translation> </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished">La etiqueta asociada con esta entrada de la lista de direcciones</translation> + <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 está en la lista de direcciones. Esto solo se puede modificar para enviar direcciones.</translation> + <translation type="unfinished">La dirección asociada con esta entrada en la lista de direcciones. Solo se puede modificar para las direcciones de envÃo.</translation> </message> <message> <source>&Address</source> - <translation type="unfinished">Y dirección</translation> + <translation type="unfinished">&Dirección</translation> </message> <message> <source>New sending address</source> - <translation type="unfinished">Nueva dirección para enviar</translation> + <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 envÃo</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 valida.</translation> + <translation type="unfinished">La dirección ingresada "%1" no es una dirección de 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 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> <message> <source>New key generation failed.</source> - <translation type="unfinished">La generación de la nueva clave fallo</translation> + <translation type="unfinished">Error al generar clave nueva.</translation> </message> </context> <context> @@ -1074,15 +1313,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>name</source> - <translation type="unfinished">Nombre</translation> + <translation type="unfinished">nombre</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation type="unfinished">El directorio ya existe. Añada %1 si pretende crear aquà un directorio nuevo.</translation> + <translation type="unfinished">El directorio ya existe. Agrega %1 si deseas crear un nuevo directorio aquÃ.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation type="unfinished">Ruta de acceso existente, pero 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> + <translation type="unfinished">No se puede crear un directorio de datos aquÃ.</translation> </message> </context> <context> @@ -1097,15 +1340,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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>(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 needed for full chain)</numerusform> - <numerusform>(%n GB needed for full chain)</numerusform> + <numerusform>(%n GB necesario para completar la cadena)</numerusform> + <numerusform>(%n GB necesarios para completar la cadena)</numerusform> </translation> </message> <message> @@ -1113,8 +1356,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Elegir directorio de datos</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">Se almacenará al menos %1 GB de información en este directorio, que aumentará con el tiempo.</translation> + </message> + <message> <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> + <translation type="unfinished">Se almacenará aproximadamente %1 GB de información en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1130,23 +1377,35 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">La billetera 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> + <translation type="unfinished">Error: No se puede crear el directorio de datos especificado "%1" .</translation> </message> <message> <source>Welcome</source> - <translation type="unfinished">bienvenido</translation> + <translation type="unfinished">Te damos la bienvenida</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation type="unfinished">Te damos la bienvenida 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> + <translation type="unfinished">Como es la primera vez que se ejecuta el programa, puedes elegir dónde %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> + <translation type="unfinished">Limitar el almacenamiento de la 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">Para revertir esta configuración, se debe descargar de nuevo la cadena de bloques completa. Es más rápido descargar la cadena completa y podarla después. Desactiva algunas funciones avanzadas.</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">La sincronización inicial consume muchos recursos y es posible que exponga problemas de hardware en la computadora que anteriormente pasaron desapercibidos. Cada vez que ejecutes %1, seguirá descargando desde el punto en el que quedó.</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> @@ -1154,20 +1413,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Si elegiste la opción de limitar el almacenamiento de la cadena de bloques (podado), los datos históricos se deben descargar y procesar de igual manera, pero se eliminarán después para disminuir el uso del disco.</translation> </message> <message> <source>Use the default data directory</source> - <translation type="unfinished">Usa el directorio de datos predeterminado</translation> + <translation type="unfinished">Usar 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> + <translation type="unfinished">Usar un directorio de datos personalizado:</translation> </message> </context> <context> <name>HelpMessageDialog</name> <message> + <source>version</source> + <translation type="unfinished">versión</translation> + </message> + <message> <source>About %1</source> <translation type="unfinished">Acerca de %1</translation> </message> @@ -1177,6 +1440,17 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> </context> <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 apagues la computadora hasta que desaparezca esta ventana.</translation> + </message> +</context> +<context> <name>ModalOverlay</name> <message> <source>Form</source> @@ -1184,31 +1458,51 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Es posible que las transacciones recientes aún no sean visibles y, por lo tanto, el saldo de la billetera podrÃa ser incorrecto. Esta información será correcta una vez que la billetera haya terminado de sincronizarse con la red de Bitcoin, como se detalla abajo.</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á si se intenta gastar bitcoins afectados por las transacciones que aún no se muestran.</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">Numero de bloques pendientes</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> <message> + <source>Progress</source> + <translation type="unfinished">Progreso</translation> + </message> + <message> <source>Progress increase per hour</source> - <translation type="unfinished">Incremento del progreso por hora</translation> + <translation type="unfinished">Avance del progreso por hora</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation type="unfinished">Tiempo estimado restante hasta la sincronización</translation> + </message> + <message> + <source>Hide</source> + <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> + <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 cabeceras (%1, %2%)…</translation> + <translation type="unfinished">Desconocido. Sincronizando encabezados (%1, %2%)…</translation> </message> <message> <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> @@ -1238,16 +1532,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">&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>&Start %1 on system login</source> - <translation type="unfinished">&Iniciar %1 al iniciar el sistema</translation> + <translation type="unfinished">&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">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> + <translation type="unfinished">Al activar el podado, 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 &database cache</source> + <translation type="unfinished">Tamaño de la caché de la &base de datos</translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">Número de hilos de &verificación de scripts</translation> + <translation type="unfinished">Número de subprocesos de &verificación de scripts</translation> </message> <message> <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> @@ -1255,15 +1557,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Dirección IP del proxy (por 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 suministrado se utiliza para llegar a los 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">Minimice en lugar de salir de la aplicación cuando la ventana esté cerrada. Cuando esta opción está habilitada, la aplicación se cerrará solo después de seleccionar Salir en el menú.</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 solo se cerrará después de seleccionar "Salir" en el menú.</translation> </message> <message> <source>Font in the Overview tab: </source> - <translation type="unfinished">Fuente en la pestaña Resumen:</translation> + <translation type="unfinished">Fuente en la pestaña "Vista general":</translation> </message> <message> <source>Options set in this dialog are overridden by the command line:</source> @@ -1286,6 +1592,10 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">&Restablecer opciones</translation> </message> <message> + <source>&Network</source> + <translation type="unfinished">&Red</translation> + </message> + <message> <source>Prune &block storage to</source> <translation type="unfinished">Podar el almacenamiento de &bloques a</translation> </message> @@ -1301,7 +1611,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Establece el número de subprocesos 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, <0 = leave that many cores free)</source> @@ -1310,7 +1620,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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 los comandos JSON-RPC.</translation> </message> <message> <source>Enable R&PC server</source> @@ -1324,7 +1634,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Si se resta o no la comisión del importe por defecto.</translation> </message> <message> <source>Subtract &fee from amount by default</source> @@ -1332,8 +1642,16 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Restar &comisión del importe por defecto</translation> </message> <message> + <source>Expert</source> + <translation type="unfinished">Experto</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation type="unfinished">Habilitar funciones de &control de monedas</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 deshabilita 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 cómo se calcula su saldo.</translation> + <translation type="unfinished">Si deshabilitas el gasto del cambio sin confirmar, no se puede usar el cambio de una transacción hasta que esta tenga al menos una confirmación. Esto también afecta cómo se calcula el saldo.</translation> </message> <message> <source>&Spend unconfirmed change</source> @@ -1342,12 +1660,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <message> <source>Enable &PSBT controls</source> <extracomment>An options window setting to enable PSBT controls.</extracomment> - <translation type="unfinished">Activar controles de &PSBT</translation> + <translation type="unfinished">Activar controles de &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">Si se muestran los controles de PSBT.</translation> + <translation type="unfinished">Si se muestran los controles de TBPF.</translation> </message> <message> <source>External Signer (e.g. hardware wallet)</source> @@ -1359,7 +1677,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Abrir automáticamente el puerto del cliente de Bitcoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation type="unfinished">Asignar puerto usando &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> @@ -1370,24 +1692,36 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Asignar puerto usando NA&T-PMP</translation> </message> <message> + <source>Accept connections from outside.</source> + <translation type="unfinished">Aceptar conexiones externas.</translation> + </message> + <message> <source>Allow incomin&g connections</source> - <translation type="unfinished">Permitir conexiones entrantes</translation> + <translation type="unfinished">&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> + <translation type="unfinished">Conectarse a la red de Bitcoin a través de un proxy SOCKS5.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation type="unfinished">&Conectarse a través del proxy SOCKS5 (proxy predeterminado):</translation> + </message> + <message> + <source>Proxy &IP:</source> + <translation type="unfinished">&IP del proxy:</translation> </message> <message> <source>&Port:</source> - <translation type="unfinished">Puerto:</translation> + <translation type="unfinished">&Puerto:</translation> </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation type="unfinished">Puerto del proxy (ej. 9050)</translation> + <translation type="unfinished">Puerto del proxy (p. ej., 9050)</translation> </message> <message> <source>Used for reaching peers via:</source> - <translation type="unfinished">Utilizado para llegar a los compañeros a través de:</translation> + <translation type="unfinished">Usado para conectarse con pares a través de:</translation> </message> <message> <source>&Window</source> @@ -1399,15 +1733,23 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>&Show tray icon</source> - <translation type="unfinished">Mostrar la &bandeja del sistema.</translation> + <translation type="unfinished">&Mostrar el Ãcono de la bandeja</translation> </message> <message> <source>Show only a tray icon after minimizing the window.</source> - <translation type="unfinished">Muestra solo un Ãcono en la bandeja después de minimizar la ventana</translation> + <translation type="unfinished">Mostrar solo un Ãcono de bandeja después de minimizar la ventana.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation type="unfinished">&Minimizar a la bandeja en vez de la barra de tareas</translation> </message> <message> <source>M&inimize on close</source> - <translation type="unfinished">Minimice al cerrar</translation> + <translation type="unfinished">&Minimizar al cerrar</translation> + </message> + <message> + <source>&Display</source> + <translation type="unfinished">&Visualización</translation> </message> <message> <source>User Interface &language:</source> @@ -1415,15 +1757,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">El idioma de la interfaz de usuario puede establecerse aquÃ. Esta configuración surtirá efecto después de reiniciar %1.</translation> </message> <message> <source>&Unit to show amounts in:</source> - <translation type="unfinished">&Unidad en la que mostrar cantitades:</translation> + <translation type="unfinished">&Unidad en la que se muestran los 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> + <translation type="unfinished">Elegir la unidad de subdivisión predeterminada para mostrar en la interfaz y al enviar 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> @@ -1431,7 +1773,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>&Third-party transaction URLs</source> - <translation type="unfinished">URLs de transacciones de &terceros</translation> + <translation type="unfinished">&URL de transacciones de terceros</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation type="unfinished">Si se muestran o no las funcionalidades de control de monedas.</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 de Bitcoin a través de un proxy SOCKS5 independiente para los servicios onion de Tor.</translation> </message> <message> <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> @@ -1439,12 +1789,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>&Cancel</source> - <translation type="unfinished">Cancelar</translation> + <translation type="unfinished">&Cancelar</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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> <message> <source>default</source> @@ -1457,7 +1807,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Confirmar restablecimiento de opciones</translation> </message> <message> <source>Client restart required to activate changes.</source> @@ -1467,12 +1817,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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 será cluasurado. Quieres proceder?</translation> + <translation type="unfinished">El cliente se cerrará. ¿Quieres continuar?</translation> </message> <message> <source>Configuration options</source> @@ -1482,7 +1832,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">El archivo de configuración se usa para especificar opciones avanzadas del usuario, que remplazan la configuración de la GUI. Además, las opciones de la lÃnea de comandos remplazarán este archivo de configuración.</translation> </message> <message> <source>Continue</source> @@ -1494,14 +1844,22 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>The configuration file could not be opened.</source> - <translation type="unfinished">El archivo de configuración no se pudo abrir.</translation> + <translation type="unfinished">No se pudo abrir el archivo de configuración.</translation> </message> - </context> + <message> + <source>This change would require a client restart.</source> + <translation type="unfinished">Estos cambios requieren reiniciar el cliente.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation type="unfinished">La dirección del proxy proporcionada es inválida.</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> + <translation type="unfinished">No se puede leer la configuración "%1", %2.</translation> </message> </context> <context> @@ -1512,7 +1870,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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 Bitcoin después de que se haya establecido una conexión, pero este proceso aún no se ha completado.</translation> + <translation type="unfinished">La información mostrada puede estar desactualizada. La billetera 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 de observación:</translation> </message> <message> <source>Available:</source> @@ -1520,7 +1882,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current spendable balance</source> - <translation type="unfinished">Su balance actual gastable</translation> + <translation type="unfinished">Tu saldo disponible para gastar actualmente</translation> </message> <message> <source>Pending:</source> @@ -1528,15 +1890,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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">Total de transacciones que aún no se han sido confirmadas, y que no son contabilizadas dentro del saldo disponible para gastar</translation> + <translation type="unfinished">Total de transacciones que aún se deben confirmar y que no se contabilizan dentro del saldo disponible para gastar</translation> </message> <message> <source>Immature:</source> - <translation type="unfinished">No disponible:</translation> + <translation type="unfinished">Inmaduro:</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> + <translation type="unfinished">Saldo minado que aún no ha madurado</translation> </message> <message> <source>Balances</source> @@ -1544,15 +1906,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current total balance</source> - <translation type="unfinished">Saldo total actual</translation> + <translation type="unfinished">Tu saldo total actual</translation> </message> <message> <source>Your current balance in watch-only addresses</source> - <translation type="unfinished">Tu saldo actual en solo ver direcciones</translation> + <translation type="unfinished">Tu saldo actual en direcciones solo de observación</translation> </message> <message> <source>Spendable:</source> - <translation type="unfinished">Disponible:</translation> + <translation type="unfinished">Gastable:</translation> </message> <message> <source>Recent transactions</source> @@ -1560,30 +1922,34 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation type="unfinished">Transacciones sin confirmar a direcciones de observación</translation> + <translation type="unfinished">Transacciones sin confirmar hacia direcciones solo 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 solo de observación que aún no ha madurado</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation type="unfinished">Saldo total actual en direcciones de observación</translation> + <translation type="unfinished">Saldo total actual en direcciones solo de observación</translation> </message> <message> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->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->Ocultar valores.</translation> + <translation type="unfinished">Modo de privacidad activado para la pestaña de vista general. Para mostrar los valores, anula la selección de "Configuración->Ocultar valores".</translation> </message> </context> <context> <name>PSBTOperationsDialog</name> <message> <source>PSBT Operations</source> - <translation type="unfinished">Operaciones PSBT</translation> + <translation type="unfinished">Operaciones TBPF</translation> </message> <message> <source>Sign Tx</source> - <translation type="unfinished">Firmar Tx</translation> + <translation type="unfinished">Firmar transacción</translation> </message> <message> <source>Broadcast Tx</source> - <translation type="unfinished">Emitir Tx</translation> + <translation type="unfinished">Transmitir transacción</translation> </message> <message> <source>Copy to Clipboard</source> @@ -1599,7 +1965,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Failed to load transaction: %1</source> - <translation type="unfinished">Error en la carga de la transacción: %1</translation> + <translation type="unfinished">Error al cargar la transacción: %1</translation> </message> <message> <source>Failed to sign transaction: %1</source> @@ -1610,22 +1976,34 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 pudieron firmar más entradas.</translation> + </message> + <message> <source>Signed %1 inputs, but more signatures are still required.</source> - <translation type="unfinished">Se han firmado %1 entradas, pero aún se requieren más firmas.</translation> + <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">Se ha firmado correctamente. La transacción está lista para difundirse.</translation> + <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 ha difundido correctamente! Código ID de la transacción: %1</translation> + <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">TBPF copiada al portapapeles.</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">Guardar datos de la transacción</translation> </message> @@ -1636,7 +2014,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT guardada en en el disco.</translation> + <translation type="unfinished">TBPF guardada en el disco.</translation> </message> <message> <source>Sends %1 to %2</source> @@ -1644,19 +2022,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>own address</source> - <translation type="unfinished">dirección personal</translation> + <translation type="unfinished">dirección propia</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 del importe de la transacción.</translation> + <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">Pagar comisión de transacción:</translation> + <translation type="unfinished">Paga comisión de transacción:</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>or</source> @@ -1664,17 +2042,37 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Transaction has %1 unsigned inputs.</source> - <translation type="unfinished">La transacción tiene %1 entradas no firmadas.</translation> + <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">Falta alguna información sobre las entradas de la transacción.</translation> + <translation type="unfinished">Falta información sobre las entradas de la transacción.</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> - </context> + <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> +</context> <context> <name>PaymentServer</name> <message> @@ -1682,20 +2080,32 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 el controlador "bitcoin: click-to-pay"</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> + <translation type="unfinished">"bitcoin://" no es un URI válido. Usa "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 debido a que no se soporta BIP70. -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> + <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 recibes este error, debes solicitar al comerciante que te 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">No se puede analizar el URI. Esto se puede deber a una dirección de Bitcoin inválida o a parámetros de URI con formato incorrecto.</translation> </message> <message> <source>Payment request file handling</source> - <translation type="unfinished">Manejo del archivo de solicitud de pago</translation> + <translation type="unfinished">Gestión del archivo de solicitud de pago</translation> </message> </context> <context> @@ -1713,12 +2123,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Antigüedad</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> </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">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>Received</source> @@ -1748,7 +2163,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>Outbound</source> <extracomment>An Outbound Connection to a Peer.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> </context> <context> @@ -1758,8 +2173,16 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">&Guardar imagen...</translation> </message> <message> + <source>&Copy Image</source> + <translation type="unfinished">&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> + <translation type="unfinished">El URI resultante es demasiado largo, asà que trata 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> @@ -1782,24 +2205,32 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">N/D</translation> </message> <message> + <source>Client version</source> + <translation type="unfinished">Versión del cliente</translation> + </message> + <message> <source>&Information</source> <translation type="unfinished">&Información</translation> </message> <message> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de datos, usa la opción "%1".</translation> </message> <message> <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <translation type="unfinished">Directorio de bloques</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de bloques, usa la opción "%1".</translation> </message> <message> <source>Startup time</source> - <translation type="unfinished">Hora de inicio</translation> + <translation type="unfinished">Tiempo de inicio</translation> </message> <message> <source>Network</source> @@ -1819,19 +2250,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Memory Pool</source> - <translation type="unfinished">Grupo de memoria</translation> + <translation type="unfinished">Pool de memoria</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation type="unfinished">Número total de transacciones</translation> </message> <message> <source>Memory usage</source> - <translation type="unfinished">Memoria utilizada</translation> + <translation type="unfinished">Uso de memoria</translation> </message> <message> <source>Wallet: </source> - <translation type="unfinished">Monedero:</translation> + <translation type="unfinished">Billetera:</translation> + </message> + <message> + <source>(none)</source> + <translation type="unfinished">(ninguna)</translation> </message> <message> <source>&Reset</source> - <translation type="unfinished">&Reestablecer</translation> + <translation type="unfinished">&Restablecer</translation> </message> <message> <source>Received</source> @@ -1839,7 +2278,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Sent</source> - <translation type="unfinished">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>&Peers</source> @@ -1863,13 +2302,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Cadena de identificación de la sesión BIP324 en formato hexadecimal, si existe.</translation> + <translation type="unfinished">Cadena de identificador de la sesión BIP324 en formato hexadecimal, si existe.</translation> </message> <message> <source>Session ID</source> <translation type="unfinished">Identificador de sesión</translation> </message> <message> + <source>Version</source> + <translation type="unfinished">Versión</translation> + </message> + <message> <source>Whether we relay transactions to this peer.</source> <translation type="unfinished">Si retransmitimos las transacciones a este par.</translation> </message> @@ -1879,19 +2322,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Starting Block</source> - <translation type="unfinished">Bloque de inicio</translation> + <translation type="unfinished">Bloque inicial</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> + <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> @@ -1901,17 +2352,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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">Transmisión de la dirección</translation> + <translation type="unfinished">Retransmisión de direcciones</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 han sido procesadas (excluyendo las direcciones que han sido desestimadas debido a la limitación de velocidad).</translation> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se procesaron (excluye las direcciones desestimadas 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 han sido desestimadas (no procesadas) debido a la limitación de velocidad.</translation> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se desestimaron (no se procesaron) debido a la limitación de volumen.</translation> </message> <message> <source>Addresses Processed</source> @@ -1921,7 +2372,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Direcciones desestimadas por limitación de volumen</translation> </message> <message> <source>User Agent</source> @@ -1929,7 +2380,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Current block height</source> @@ -1937,15 +2388,19 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> + <translation type="unfinished">Abrir el archivo de registro de depuración %1 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> </message> <message> <source>Decrease font size</source> - <translation type="unfinished">Reducir el tamaño de la fuente</translation> + <translation type="unfinished">Disminuir tamaño de fuente</translation> </message> <message> <source>Increase font size</source> - <translation type="unfinished">Aumentar el tamaño de la fuente</translation> + <translation type="unfinished">Aumentar tamaño de fuente</translation> + </message> + <message> + <source>Permissions</source> + <translation type="unfinished">Permisos</translation> </message> <message> <source>The direction and type of peer connection: %1</source> @@ -1957,7 +2412,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 mediante el cual está conectado este par: IPv4, IPv6, Onion, I2P o CJDNS.</translation> </message> <message> <source>Services</source> @@ -1965,13 +2420,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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> + <translation type="unfinished">Retransmisión de bloques compactos BIP152 en 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">Tiempo de 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> @@ -1990,27 +2449,35 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Last Receive</source> - <translation type="unfinished">Ultima recepción</translation> + <translation type="unfinished">Última recepción</translation> </message> <message> <source>Ping Time</source> - <translation type="unfinished">Tiempo de Ping</translation> + <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> + <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">Desfase temporal</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Hora del último bloque</translation> </message> <message> <source>&Open</source> - <translation type="unfinished">Abierto</translation> + <translation type="unfinished">&Abrir</translation> </message> <message> <source>&Console</source> @@ -2018,7 +2485,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Network Traffic</source> - <translation type="unfinished">&Tráfico de Red</translation> + <translation type="unfinished">&Tráfico de red</translation> </message> <message> <source>Totals</source> @@ -2026,11 +2493,11 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Debug log file</source> - <translation type="unfinished">Archivo de registro de depuración</translation> + <translation type="unfinished">Archivo del registro de depuración</translation> </message> <message> <source>Clear console</source> - <translation type="unfinished">Limpiar Consola</translation> + <translation type="unfinished">Borrar consola</translation> </message> <message> <source>In:</source> @@ -2038,17 +2505,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Out:</source> - <translation type="unfinished">Fuera:</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: iniciado por el par</translation> + <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: predeterminado</translation> + <translation type="unfinished">Retransmisión completa saliente: predeterminada</translation> </message> <message> <source>Outbound Block Relay: does not relay transactions or addresses</source> @@ -2063,7 +2530,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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">Tanteador de salida: de corta duración, para probar las direcciones</translation> + <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> @@ -2078,7 +2545,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>v1: unencrypted, plaintext transport protocol</source> <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">v1: protocolo de transporte de texto simple sin cifrar</translation> + <translation type="unfinished">v1: protocolo de transporte de texto simple sin encriptar</translation> </message> <message> <source>v2: BIP324 encrypted transport protocol</source> @@ -2095,7 +2562,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>no high bandwidth relay selected</source> - <translation type="unfinished">Ninguna transmisión de banda ancha seleccionada</translation> + <translation type="unfinished">No se seleccionó la retransmisión de banda ancha</translation> </message> <message> <source>&Copy address</source> @@ -2103,21 +2570,33 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">&Copiar dirección</translation> </message> <message> + <source>&Disconnect</source> + <translation type="unfinished">&Desconectar</translation> + </message> + <message> <source>1 &hour</source> - <translation type="unfinished">1 hora</translation> + <translation type="unfinished">1 &hora</translation> </message> <message> <source>1 d&ay</source> <translation type="unfinished">1 &dÃa</translation> </message> <message> + <source>1 &week</source> + <translation type="unfinished">1 &semana</translation> + </message> + <message> + <source>1 &year</source> + <translation type="unfinished">1 &año</translation> + </message> + <message> <source>&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">&Copiar IP/Máscara de red</translation> </message> <message> <source>&Unban</source> - <translation type="unfinished">&Desbloquear</translation> + <translation type="unfinished">&Levantar prohibición</translation> </message> <message> <source>Network activity disabled</source> @@ -2125,13 +2604,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Executing command without any wallet</source> - <translation type="unfinished">Ejecutar comando sin monedero</translation> + <translation type="unfinished">Ejecutar comando sin ninguna billetera</translation> </message> <message> <source>Node window - [%1]</source> <translation type="unfinished">Ventana de nodo - [%1]</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. @@ -2140,12 +2623,13 @@ 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">Bienvenido a la consola RPC -%1. Utiliza las flechas arriba y abajo para navegar por el historial, y %2 para borrar la pantalla. + <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 un resumen de los comandos disponibles. Para más información sobre cómo usar esta consola, escribe %6. +Escribe %5 para ver los comandos disponibles. +Para obtener más información sobre cómo usar esta consola, escribe %6. -%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> +%7 ADVERTENCIA: Los estafadores suelen decirles a los usuarios que escriban comandos aquà para robarles el contenido de sus billeteras. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation> </message> <message> <source>Executing…</source> @@ -2162,11 +2646,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Yes</source> - <translation type="unfinished">Si</translation> + <translation type="unfinished">SÃ</translation> </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>From</source> @@ -2174,11 +2658,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Ban for</source> - <translation type="unfinished">Bloqueo para</translation> + <translation type="unfinished">Prohibir por</translation> </message> <message> <source>Never</source> - <translation type="unfinished">nunca</translation> + <translation type="unfinished">Nunca</translation> </message> <message> <source>Unknown</source> @@ -2192,28 +2676,32 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">&Importe:</translation> </message> <message> + <source>&Label:</source> + <translation type="unfinished">&Etiqueta:</translation> + </message> + <message> <source>&Message:</source> <translation type="unfinished">&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 adjunto a la solicitud de pago, que será mostrado cuando la solicitud sea abierta. Nota: Este mensaje no será enviado con el pago a través de la red Bitcoin.</translation> + <translation type="unfinished">Mensaje opcional para adjuntar a la solicitud de pago, que se mostrará cuando se abra la solicitud. Nota: Este 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">Una etiqueta opcional para asociar con la nueva dirección de recepción</translation> + <translation type="unfinished">Una 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 <b>optional</b>.</source> - <translation type="unfinished">Use este formulario para solicitar pagos. Todos los campos son <b> opcionales </ b>.</translation> + <translation type="unfinished">Usa este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>.</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> + <translation type="unfinished">Un importe opcional para solicitar. Déjalo vacÃo o ingresa cero para no solicitar un importe 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> + <translation type="unfinished">Una etiqueta opcional para asociar con la nueva dirección de recepción (puedes usarla 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> @@ -2221,29 +2709,37 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>&Create new receiving address</source> - <translation type="unfinished">&Crear una nueva dirección de recepción</translation> + <translation type="unfinished">&Crear nueva dirección de recepción</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished">Borre todos los campos del formulario.</translation> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Clear</source> - <translation type="unfinished">Aclarar</translation> + <translation type="unfinished">Borrar</translation> </message> <message> <source>Requested payments history</source> - <translation type="unfinished">Historial de pagos solicitado</translation> + <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">Muestra la petición seleccionada (También doble clic)</translation> + <translation type="unfinished">Mostrar la solicitud seleccionada (equivale a hacer doble clic en una entrada)</translation> + </message> + <message> + <source>Show</source> + <translation type="unfinished">Mostrar</translation> </message> <message> <source>Remove the selected entries from the list</source> <translation type="unfinished">Eliminar las entradas seleccionadas de la lista</translation> </message> <message> + <source>Remove</source> + <translation type="unfinished">Eliminar</translation> + </message> + <message> <source>Copy &URI</source> <translation type="unfinished">Copiar &URI</translation> </message> @@ -2280,8 +2776,12 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Bech32m (BIP-350) es una actualización de Bech32. La compatibilidad con la billetera todavÃa es limitada.</translation> </message> <message> + <source>Could not unlock wallet.</source> + <translation type="unfinished">No se pudo desbloquear la billetera.</translation> + </message> + <message> <source>Could not generate new %1 address</source> - <translation type="unfinished">No se ha podido generar una nueva dirección %1</translation> + <translation type="unfinished">No se pudo generar nueva dirección %1</translation> </message> </context> <context> @@ -2291,16 +2791,32 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Solicitar pago a...</translation> </message> <message> + <source>Address:</source> + <translation type="unfinished">Dirección:</translation> + </message> + <message> <source>Amount:</source> <translation type="unfinished">Importe:</translation> </message> <message> + <source>Label:</source> + <translation type="unfinished">Etiqueta:</translation> + </message> + <message> + <source>Message:</source> + <translation type="unfinished">Mensaje:</translation> + </message> + <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> <source>Copy &URI</source> <translation type="unfinished">Copiar &URI</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished">&Copia dirección</translation> + <translation type="unfinished">Copiar &dirección</translation> </message> <message> <source>&Verify</source> @@ -2308,18 +2824,34 @@ 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, por ejemplo, en la pantalla de una billetera de hardware</translation> + <translation type="unfinished">Verificar esta dirección, por ejemplo, en la pantalla de una billetera de hardware.</translation> </message> <message> <source>&Save Image…</source> <translation type="unfinished">&Guardar imagen...</translation> </message> - </context> + <message> + <source>Payment information</source> + <translation type="unfinished">Información del pago</translation> + </message> + <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">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> + </message> + <message> + <source>Message</source> + <translation type="unfinished">Mensaje</translation> </message> <message> <source>(no label)</source> @@ -2331,7 +2863,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>(no amount requested)</source> - <translation type="unfinished">(sin importe solicitado)</translation> + <translation type="unfinished">(no se solicitó un importe)</translation> </message> <message> <source>Requested</source> @@ -2346,11 +2878,15 @@ 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 moneda</translation> + <translation type="unfinished">Funciones de control de monedas</translation> + </message> + <message> + <source>automatically selected</source> + <translation type="unfinished">seleccionado automáticamente</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished">Fondos insuficientes!</translation> + <translation type="unfinished">Fondos insuficientes</translation> </message> <message> <source>Quantity:</source> @@ -2369,20 +2905,36 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Después de la comisión:</translation> </message> <message> + <source>Change:</source> + <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> + <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 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> + <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> - <translation type="unfinished">Advertencia: En este momento no se puede estimar la cuota.</translation> + <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> @@ -2394,11 +2946,15 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Send to multiple recipients at once</source> - <translation type="unfinished">Enviar a múltiples destinatarios</translation> + <translation type="unfinished">Enviar a múltiples destinatarios a la vez</translation> + </message> + <message> + <source>Add &Recipient</source> + <translation type="unfinished">Agregar &destinatario</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished">Borre todos los campos del formulario.</translation> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Inputs…</source> @@ -2422,23 +2978,31 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <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">Una comisión demasiado pequeña puede resultar en una transacción que nunca será confirmada (leer herramientas de información).</translation> + <translation type="unfinished">Si la comisión es demasiado baja, es posible que la transacción nunca se confirme (leer la información en pantalla).</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 "Remplazar 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> + <translation type="unfinished">Con la función "Remplazar 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 &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>Balance:</source> @@ -2446,7 +3010,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Confirm the send action</source> - <translation type="unfinished">Confirma el envio</translation> + <translation type="unfinished">Confirmar el envÃo</translation> + </message> + <message> + <source>S&end</source> + <translation type="unfinished">&Enviar</translation> </message> <message> <source>Copy quantity</source> @@ -2454,15 +3022,27 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>Copy fee</source> - <translation type="unfinished">Tarifa de copia</translation> + <translation type="unfinished">Copiar comisión</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de la tarifa</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 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> @@ -2471,16 +3051,24 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Conecta tu monedero externo primero.</translation> + <translation type="unfinished">Conecta primero tu billetera de hardware.</translation> </message> <message> <source>Set external signer script path in Options -> Wallet</source> <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Configura una ruta externa al script en Opciones -> Monedero</translation> + <translation type="unfinished">Establecer la ruta al script del firmante externo en "Opciones -> Billetera"</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation type="unfinished">&Crear 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> + <translation type="unfinished">Crea una transacción de Bitcoin parcialmente firmada (TBPF) para usarla, por ejemplo, con una billetera %1 sin conexión o una billetera de hardware compatible con TBPF.</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation type="unfinished">%1 a '%2'</translation> </message> <message> <source>%1 to %2</source> @@ -2492,17 +3080,17 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Sign failed</source> - <translation type="unfinished">La firma falló</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <translation type="unfinished">Error de firmante externo</translation> </message> <message> <source>Save Transaction Data</source> @@ -2516,7 +3104,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">TBPF guardado </translation> + <translation type="unfinished">TBPF guardada</translation> </message> <message> <source>External balance:</source> @@ -2528,11 +3116,16 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Puedes aumentar la comisión después (indica "Remplazar 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 (TBPF) que puedes guardar o copiar y, luego, firmar; por ejemplo, una billetera %1 fuera de lÃnea o una billetera de hardware compatible con TBPF.</translation> </message> <message> <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 desde monedero '%2'</translation> + <translation type="unfinished">%1 desde billetera "%2"</translation> </message> <message> <source>Do you want to create this transaction?</source> @@ -2542,38 +3135,42 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">Revisa la transacción. Puedes crear y enviar esta transacción de Bitcoin parcialmente firmada (TBPF), 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 TBPF.</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, revisa tu transacción</translation> + <translation type="unfinished">Revisa la transacción.</translation> </message> <message> <source>Transaction fee</source> - <translation type="unfinished">Comisión por transacción.</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> + <translation type="unfinished">No indica "Remplazar por comisión", BIP-125.</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>Unsigned Transaction</source> <comment>PSBT copied</comment> <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> - <translation type="unfinished">Transacción no asignada</translation> + <translation type="unfinished">Transacción sin firmar</translation> </message> <message> <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">Se copió la PSBT al portapapeles. También puedes guardarla.</translation> + <translation type="unfinished">Se copió la TBPF al portapapeles. También puedes guardarla.</translation> </message> <message> <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT guardada en el disco</translation> + <translation type="unfinished">TBPF guardada en el disco</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> @@ -2585,7 +3182,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">La cantidad por pagar tiene que ser mayor que 0.</translation> + <translation type="unfinished">El importe por pagar tiene que ser mayor que 0.</translation> </message> <message> <source>The amount exceeds your balance.</source> @@ -2593,38 +3190,42 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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 tasa de envÃo de %1</translation> + <translation type="unfinished">El total sobrepasa el saldo cuando se incluye la comisión de transacción de %1.</translation> </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> <translation type="unfinished">Se encontró una dirección duplicada: las direcciones solo se deben usar 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 absurda-mente alta.</translation> + <translation type="unfinished">Una comisión mayor que %1 se considera absurdamente alta.</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Estimado para comenzar confirmación dentro de %n bloque.</numerusform> - <numerusform>Estimado para comenzar confirmación dentro de %n bloques.</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> <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">Alerta: Dirección de Bitcoin inválida</translation> + <translation type="unfinished">Advertencia: Dirección de Bitcoin inválida</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation type="unfinished">Peligro: Dirección de cambio desconocida</translation> + <translation type="unfinished">Advertencia: Dirección de cambio desconocida</translation> </message> <message> <source>Confirm custom change address</source> - <translation type="unfinished">Confirmar dirección de cambio personalizada</translation> + <translation type="unfinished">Confirmar la 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> + <translation type="unfinished">La dirección que seleccionaste para el cambio no es parte de esta billetera. Una parte o la totalidad de los fondos en la billetera se enviará a esta dirección. ¿Seguro deseas continuar?</translation> </message> <message> <source>(no label)</source> @@ -2635,11 +3236,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation type="unfinished">Ca&ntidad:</translation> + <translation type="unfinished">&Importe:</translation> </message> <message> <source>Pay &To:</source> - <translation type="unfinished">&Pagar a:</translation> + <translation type="unfinished">Pagar &a:</translation> + </message> + <message> + <source>&Label:</source> + <translation type="unfinished">&Etiqueta:</translation> </message> <message> <source>Choose previously used address</source> @@ -2647,7 +3252,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">La dirección de Bitcoin a la que se enviará el pago</translation> </message> <message> <source>Paste address from clipboard</source> @@ -2662,16 +3267,28 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 importe que se envÃa. El destinatario recibirá menos bitcoins que los que ingreses en el campo del importe. Si se seleccionan varios destinatarios, la comisión se dividirá por igual.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation type="unfinished">&Restar la comisión del importe</translation> + </message> + <message> <source>Use available balance</source> <translation type="unfinished">Usar el saldo disponible</translation> </message> <message> + <source>Message:</source> + <translation type="unfinished">Mensaje:</translation> + </message> + <message> <source>Enter a label for this address to add it to the list of used addresses</source> <translation type="unfinished">Ingresar una etiqueta para esta dirección a fin de agregarla 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á enviado a través de la red de Bitcoin.</translation> + <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> @@ -2689,19 +3306,19 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Firmas - Firmar / verificar un mensaje</translation> + <translation type="unfinished">Firmas: firmar o verificar un mensaje</translation> </message> <message> <source>&Sign Message</source> - <translation type="unfinished">&Firmar Mensaje</translation> + <translation type="unfinished">&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> + <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">La dirección Bitcoin con la que se firmó el mensaje</translation> + <translation type="unfinished">La dirección de Bitcoin con la que se firmará el mensaje</translation> </message> <message> <source>Choose previously used address</source> @@ -2712,6 +3329,10 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> <message> + <source>Enter the message you want to sign here</source> + <translation type="unfinished">Ingresar aquà el mensaje que deseas firmar</translation> + </message> + <message> <source>Signature</source> <translation type="unfinished">Firma</translation> </message> @@ -2721,27 +3342,31 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Firmar el mensaje para demostrar que esta dirección de Bitcoin te pertenece</translation> </message> <message> <source>Sign &Message</source> - <translation type="unfinished">Firmar Mensaje</translation> + <translation type="unfinished">Firmar &mensaje</translation> </message> <message> <source>Reset all sign message fields</source> - <translation type="unfinished">Limpiar todos los campos de la firma de mensaje</translation> + <translation type="unfinished">Restablecer todos los campos de firma de mensaje</translation> </message> <message> <source>Clear &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>&Verify Message</source> - <translation type="unfinished">&Firmar Mensaje</translation> + <translation type="unfinished">&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">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> + <translation type="unfinished">La dirección de Bitcoin con la que se firmó el mensaje</translation> </message> <message> <source>The signed message to verify</source> @@ -2749,39 +3374,51 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The signature given when the message was signed</source> - <translation type="unfinished">La firma proporcionada cuando el mensaje fue firmado</translation> + <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">Verifique el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation> + <translation type="unfinished">Verifica el mensaje para asegurarte de que se firmó con la dirección de Bitcoin especificada.</translation> </message> <message> <source>Verify &Message</source> <translation type="unfinished">Verificar &mensaje</translation> </message> <message> + <source>Reset all verify message fields</source> + <translation type="unfinished">Restablecer todos los campos de 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> + <translation type="unfinished">Hacer clic en "Firmar mensaje" para generar una firma</translation> </message> <message> <source>The entered address is invalid.</source> - <translation type="unfinished">La dirección introducida es inválida</translation> + <translation type="unfinished">La dirección ingresada 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> + <translation type="unfinished">Revisa la dirección e intenta de nuevo.</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> + <translation type="unfinished">La dirección ingresada no corresponde a una clave.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation type="unfinished">Se canceló el desbloqueo de la billetera.</translation> </message> <message> <source>No error</source> - <translation type="unfinished">No hay error</translation> + <translation type="unfinished">Sin error </translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation type="unfinished">La clave privada para la dirección ingresada no está disponible.</translation> </message> <message> <source>Message signing failed.</source> - <translation type="unfinished">Ha fallado la firma del mensaje.</translation> + <translation type="unfinished">Error al firmar el mensaje.</translation> </message> <message> <source>Message signed.</source> @@ -2793,30 +3430,43 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Please check the signature and try again.</source> - <translation type="unfinished">Compruebe la firma e inténtelo de nuevo.</translation> + <translation type="unfinished">Comprueba la firma e intenta 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> + <translation type="unfinished">La firma no coincide con la sÃntesis del mensaje.</translation> </message> - </context> + <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> <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(presione la tecla q para apagar y continuar después)</translation> + <translation type="unfinished">(Presionar q para apagar y seguir luego)</translation> </message> <message> <source>press q to shutdown</source> - <translation type="unfinished">pulse q para apagar</translation> + <translation type="unfinished">Presionar 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 una transacción con %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> + <translation type="unfinished">0/sin confirmar, en el pool de memoria</translation> </message> <message> <source>0/unconfirmed, not in memory pool</source> @@ -2836,33 +3486,57 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <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> + <message> <source>Source</source> <translation type="unfinished">Fuente</translation> </message> <message> + <source>Generated</source> + <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> + <translation type="unfinished">A</translation> </message> <message> <source>own address</source> - <translation type="unfinished">dirección personal</translation> + <translation type="unfinished">dirección propia</translation> + </message> + <message> + <source>watch-only</source> + <translation type="unfinished">Solo de 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>disponible en %n bloque</numerusform> - <numerusform>disponible en %n bloques</numerusform> + <numerusform>madura en %n bloque más</numerusform> + <numerusform>madura en %n bloques más</numerusform> </translation> </message> <message> @@ -2870,16 +3544,32 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 enviado</translation> + <translation type="unfinished">Débito total</translation> + </message> + <message> + <source>Total credit</source> + <translation type="unfinished">Crédito total</translation> </message> <message> <source>Transaction fee</source> - <translation type="unfinished">Comisión por transacción.</translation> + <translation type="unfinished">Comisión de transacción</translation> </message> <message> <source>Net amount</source> - <translation type="unfinished">Cantidad total</translation> + <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> @@ -2887,7 +3577,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Transaction total size</source> - <translation type="unfinished">Tamaño total transacción</translation> + <translation type="unfinished">Tamaño total de transacción</translation> </message> <message> <source>Transaction virtual size</source> @@ -2895,7 +3585,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Output index</source> - <translation type="unfinished">Indice de salida</translation> + <translation type="unfinished">Ãndice de salida</translation> </message> <message> <source>%1 (Certificate was not verified)</source> @@ -2903,11 +3593,19 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Merchant</source> - <translation type="unfinished">Vendedor</translation> + <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 meterse 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 pocos segundos del tuyo.</translation> + <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> + <message> + <source>Transaction</source> + <translation type="unfinished">Transacción</translation> </message> <message> <source>Inputs</source> @@ -2915,41 +3613,65 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Amount</source> - <translation type="unfinished">Monto</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>true</source> <translation type="unfinished">verdadero</translation> </message> - </context> + <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">Este panel muestra una descripción detallada de la transacción</translation> + <translation type="unfinished">En este panel se muestra una descripción detallada de la transacción</translation> </message> - </context> + <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">Nombre</translation> + <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> + <translation type="unfinished">Inmadura (%1 confirmaciones; estará disponibles después de %2)</translation> </message> <message> <source>Generated but not accepted</source> @@ -2957,11 +3679,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Received with</source> - <translation type="unfinished">Recibido con</translation> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Received from</source> - <translation type="unfinished">Recibido de</translation> + <translation type="unfinished">Recibida de</translation> </message> <message> <source>Sent to</source> @@ -2969,17 +3691,41 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> + </message> + <message> + <source>watch-only</source> + <translation type="unfinished">Solo de observación</translation> + </message> + <message> + <source>(n/a)</source> + <translation type="unfinished">(n/d)</translation> </message> <message> <source>(no label)</source> <translation type="unfinished">(sin etiqueta)</translation> </message> <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation type="unfinished">Estado de la transacción. Pasa el mouse 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 en las que 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 solo de 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">Importe restado del saldo o sumado a este.</translation> </message> @@ -2987,6 +3733,14 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> @@ -2996,11 +3750,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Last month</source> - <translation type="unfinished">El mes pasado </translation> + <translation type="unfinished">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> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Sent to</source> @@ -3008,7 +3766,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> </message> <message> <source>Other</source> @@ -3016,7 +3774,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Ingresar la dirección, el identificador de transacción o la etiqueta para buscar</translation> </message> <message> <source>Min amount</source> @@ -3040,11 +3798,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy transaction &ID</source> - <translation type="unfinished">Copiar &ID de la transacción</translation> + <translation type="unfinished">Copiar &identificador de transacción</translation> </message> <message> <source>Copy &raw transaction</source> - <translation type="unfinished">Copiar transacción &raw</translation> + <translation type="unfinished">Copiar transacción &sin procesar</translation> </message> <message> <source>Copy full transaction &details</source> @@ -3085,32 +3843,44 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <translation type="unfinished">Confirmada</translation> </message> <message> + <source>Watch-only</source> + <translation type="unfinished">Solo de 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">Nombre</translation> + <translation type="unfinished">Etiqueta</translation> </message> <message> <source>Address</source> <translation type="unfinished">Dirección</translation> </message> <message> + <source>ID</source> + <translation type="unfinished">Identificador</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Error al exportar</translation> </message> <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 la transacción con %1.</translation> + <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 satisfactoria</translation> + <translation type="unfinished">Exportación correcta</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> + <translation type="unfinished">El historial de transacciones se guardó correctamente en %1.</translation> </message> <message> <source>Range:</source> @@ -3128,22 +3898,34 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k Go to File > Open Wallet to load a wallet. - OR -</source> <translation type="unfinished">No se cargó ninguna billetera. -Ir a Archivo > Abrir billetera para cargar una. -- OR -</translation> +Ir a "Archivo > Abrir billetera" para cargar una. +- O -</translation> </message> <message> <source>Create a new wallet</source> - <translation type="unfinished">Crear monedero nuevo</translation> + <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 TBPF desde el portapapeles (inválido base64)</translation> + <translation type="unfinished">No se puede decodificar la TBPF desde el portapapeles (Base64 inválida)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation type="unfinished">Cargar datos de la transacción</translation> </message> <message> <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished">Transacción firmada de manera parcial (*.psbt)</translation> + <translation type="unfinished">Transacción parcialmente firmada (*.psbt)</translation> </message> - </context> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <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">No se puede decodificar TBPF</translation> + </message> +</context> <context> <name>WalletModel</name> <message> @@ -3152,20 +3934,32 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Fee bump error</source> - <translation type="unfinished">Error de incremento de cuota</translation> + <translation type="unfinished">Error de incremento de comisión</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation type="unfinished">Fallo al incrementar 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 cuota?</translation> + <translation type="unfinished">¿Deseas 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 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> + <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> @@ -3173,11 +3967,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Can't draft transaction.</source> - <translation type="unfinished">No se pudo preparar la transacción.</translation> + <translation type="unfinished">No se puede crear un borrador de la transacción.</translation> </message> <message> <source>PSBT copied</source> - <translation type="unfinished">TBPF copiada </translation> + <translation type="unfinished">TBPF copiada</translation> </message> <message> <source>Copied to clipboard</source> @@ -3186,7 +3980,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Can't sign transaction.</source> - <translation type="unfinished">No se ha podido firmar la transacción.</translation> + <translation type="unfinished">No se puede firmar la transacción.</translation> </message> <message> <source>Could not commit transaction</source> @@ -3198,18 +3992,22 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> </context> <context> <name>WalletView</name> <message> + <source>&Export</source> + <translation type="unfinished">&Exportar</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar a un archivo los datos de esta pestaña</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> <source>Backup Wallet</source> - <translation type="unfinished">Respaldo de monedero</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera</translation> </message> <message> <source>Wallet Data</source> @@ -3222,11 +4020,11 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">Ocurrió un error al intentar guardar los datos de la billetera en %1.</translation> </message> <message> <source>Backup Successful</source> - <translation type="unfinished">Respaldo exitoso</translation> + <translation type="unfinished">Copia de seguridad correcta</translation> </message> <message> <source>The wallet data was successfully saved to %1.</source> @@ -3245,11 +4043,11 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">%s dañado. Trata de usar la herramienta de la billetera de Bitcoin para rescatar o restaurar una copia de seguridad.</translation> </message> <message> <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> - <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea no válida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Comunique este incidente a %s, indicando cómo obtuvo la instantánea. Se dejó el estado de encadenamiento de la instantánea no válida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> + <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea inválida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Reporta este incidente a %s, indicando cómo obtuviste la instantánea. Se dejó el estado de cadena de la instantánea inválida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> </message> <message> <source>%s request to listen on port %u. This port is considered "bad" 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> @@ -3260,6 +4058,10 @@ Ir a Archivo > Abrir billetera para cargar una. <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> @@ -3268,28 +4070,32 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Es posible que el espacio en disco %s no tenga capacidad para los archivos de bloque. Aproximadamente %u GB de datos se almacenarán en este directorio.</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; ver el archivo adjunto %s o %s.</translation> + </message> + <message> <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">Error al cargar la billetera. Esta requiere que se descarguen bloques, y el software actualmente no admite la carga de billeteras mientras los bloques se descargan fuera de orden, cuando se usan instantáneas de assumeutxo. La billetera deberÃa poder cargarse correctamente después de que la sincronización del nodo alcance la altura %s.</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 del monedero.</translation> + <translation type="unfinished">¡Error al leer %s! Es probable que falten los datos de la transacción o que sean incorrectos. Rescaneando 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», del «formato» esperado.</translation> + <translation type="unfinished">Error: El registro del formato del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: El registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: La versión del archivo de 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> + <translation type="unfinished">Error: Las billeteras "legacy" solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32".</translation> </message> <message> <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> @@ -3301,7 +4107,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El archivo peers.dat (%s) es inválido o está dañado. 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>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> @@ -3309,15 +4115,15 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">No se proporcionó ningún archivo de volcado. Para usar createfromdump, se debe proporcionar -dumpfile=<filename>.</translation> + <translation type="unfinished">No se proporcionó el archivo de volcado. Para usar createfromdump, se debe proporcionar -dumpfile=<filename>.</translation> </message> <message> <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> - <translation type="unfinished">No se proporcionó ningún archivo de volcado. Para usar dump, se debe proporcionar -dumpfile=<filename>.</translation> + <translation type="unfinished">No se proporcionó el archivo de volcado. Para usar dump, se debe proporcionar -dumpfile=<filename>.</translation> </message> <message> <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <translation type="unfinished">No se proporcionó el formato de archivo de billetera. Para usar createfromdump, se debe proporcionar -format=<filename>.</translation> + <translation type="unfinished">No se proporcionó el formato de archivo de billetera. Para usar createfromdump, se debe proporcionar -format=<format>.</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> @@ -3328,6 +4134,10 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation type="unfinished">La poda se configuró por debajo del mÃnimo de %d MiB. Usa un valor más alto.</translation> + </message> + <message> <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> <translation type="unfinished">El modo de poda es incompatible con -reindex-chainstate. Usa en su lugar un -reindex completo.</translation> </message> @@ -3337,11 +4147,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>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.</source> - <translation type="unfinished">Error de renombrado de «%s» → «%s». DeberÃa resolver esto manualmente moviendo o borrando el directorio %s de la instantánea no válida, en otro caso encontrará el mismo error de nuevo en el arranque siguiente.</translation> + <translation type="unfinished">Error al cambiar el nombre de "%s" a "%s". Para resolverlo, mueve o elimina manualmente el directorio %s de la instantánea no válida. De lo contrario, encontrarás el mismo error de nuevo en el siguiente inicio.</translation> </message> <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> - <translation type="unfinished">SQLiteDatabase: versión desconocida del esquema de la billetera sqlite %d. Solo se admite la versión %d</translation> + <translation type="unfinished">SQLiteDatabase: versión desconocida del esquema de la billetera sqlite %d. Solo se admite la versión %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> @@ -3349,7 +4159,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El importe de la transacción es demasiado pequeño para enviarlo después de deducir 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> @@ -3365,27 +4175,27 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">Esta es la comisión de transacción que puedes descartar si el cambio es más pequeño que el remanente en este nivel.</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">Impuesto por transacción que pagarás cuando la estimación de impuesto no esté disponible.</translation> + <translation type="unfinished">Esta es la comisión de transacción que puedes pagar cuando los cálculos de comisiones no estén disponibles.</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> + <translation type="unfinished">La longitud total de la cadena de versión de red ( %i) supera la longitud máxima (%i). Reduce 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 pudieron reproducir bloques. Tendrás que reconstruir la base de datos usando -reindex-chainstate.</translation> + <translation type="unfinished">No se pueden reproducir bloques. Tendrás que reconstruir la base de datos usando -reindex-chainstate.</translation> </message> <message> <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> - <translation type="unfinished">Se proporcionó un formato de billetera desconocido "%s". Proporciona uno entre "bdb" o "sqlite".</translation> + <translation type="unfinished">Se proporcionó un formato de archivo de billetera desconocido "%s". Proporciona uno entre "bdb" o "sqlite".</translation> </message> <message> <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <translation type="unfinished">Nivel de boletÃn del acceso especificado en categorÃa no mantenida en %1$s=%2$s. Se esperaba %1$s=1:2. CategorÃas válidas: %3$s. Niveles de boletÃn válidos: %4 $s.</translation> + <translation type="unfinished">El nivel de registro de la categorÃa especÃfica no es compatible: %1$s=%2$s. Se esperaba %1$s=<category>:<loglevel>. CategorÃas válidas: %3$s. Niveles de registro válidos: %4 $s.</translation> </message> <message> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> @@ -3397,11 +4207,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> - <translation type="unfinished">Monedero correctamente cargado. El tipo de billetero heredado está siendo obsoleto y mantenimiento para creación de monederos heredados serán eliminados en el futuro. Los monederos heredados pueden ser migrados a un descriptor de monedero con migratewallet.</translation> + <translation type="unfinished">La billetera se creó correctamente. El tipo de billetera "legacy" se está descontinuando, por lo que la asistencia para crear y abrir estas billeteras se eliminará en el futuro. Las billeteras "legacy" se pueden migrar a una billetera basada en descriptores con "migratewallet".</translation> </message> <message> <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <translation type="unfinished">Advertencia: el formato de la billetera del archivo de volcado "%s" no coincide con el formato especificado en la lÃnea de comandos "%s".</translation> + <translation type="unfinished">Advertencia: El formato de la billetera 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> @@ -3409,7 +4219,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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: ¡Al parecer no estamos completamente de acuerdo con nuestros pares! Es posible que tengas que actualizarte, o que los demás nodos tengan que hacerlo.</translation> + <translation type="unfinished">Advertencia: Al parecer no estamos completamente de acuerdo con nuestros pares. Es posible que tengas que realizar una actualización, o que los demás nodos tengan que hacerlo.</translation> </message> <message> <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> @@ -3421,7 +4231,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>%s is set very high!</source> - <translation type="unfinished">¡%s esta configurado muy alto!</translation> + <translation type="unfinished">¡El valor de %s es muy alto!</translation> </message> <message> <source>-maxmempool must be at least %d MB</source> @@ -3433,7 +4243,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">No se puede resolver -%s direccion: '%s'</translation> + <translation type="unfinished">No se puede resolver la dirección de -%s: "%s"</translation> </message> <message> <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> @@ -3461,7 +4271,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> - <translation type="unfinished">Error leyendo %s. Todas las teclas leÃdas correctamente, pero los datos de transacción o metadatos de dirección puedan ser ausentes o incorrectos.</translation> + <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 metadatos de direcciones, o bien que sean incorrectos.</translation> </message> <message> <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> @@ -3513,11 +4323,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> - <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar una cantidad menor o consolidar manualmente las UTXO de la billetera.</translation> + <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</translation> </message> <message> <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">La cantidad total de monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> + <translation type="unfinished">El monto total de las monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> </message> <message> <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> @@ -3529,14 +4339,14 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> - <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará el pool de memoria.</translation> + <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará la mempool.</translation> </message> <message> <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">Se encontró una entrada heredada inesperada en la billetera del descriptor. Cargando billetera%s + <translation type="unfinished">Se encontró una entrada inesperada tipo "legacy" en la billetera basada en descriptores. Cargando billetera%s Es posible que la billetera haya sido manipulada o creada con malas intenciones. </translation> @@ -3570,6 +4380,18 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Se interrumpió la verificación de bloques</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation type="unfinished">La configuración para %s solo se aplica en la red %s cuando se encuentra en la sección [%s].</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation type="unfinished">Derechos de autor (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation type="unfinished">Se detectó que la base de datos de bloques está dañada.</translation> + </message> + <message> <source>Could not find asmap file %s</source> <translation type="unfinished">No se pudo encontrar el archivo asmap %s</translation> </message> @@ -3582,6 +4404,14 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">¡El espacio en 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> @@ -3594,16 +4424,36 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Error al crear %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 de la billetera %s.</translation> + </message> + <message> + <source>Error loading %s</source> + <translation type="unfinished">Error al cargar %s</translation> + </message> + <message> <source>Error loading %s: Private keys can only be disabled during creation</source> <translation type="unfinished">Error al cargar %s: Las claves privadas solo se pueden deshabilitar durante la creación</translation> </message> <message> <source>Error loading %s: Wallet corrupted</source> - <translation type="unfinished">Error cargando %s: Monedero corrupto</translation> + <translation type="unfinished">Error al cargar %s: billetera dañada</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> + <translation type="unfinished">Error al cargar %s: la billetera requiere una versión más reciente de %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation type="unfinished">Error al cargar la base de datos de bloques</translation> + </message> + <message> + <source>Error opening block database</source> + <translation type="unfinished">Error al abrir la base de datos de bloques</translation> </message> <message> <source>Error reading configuration file: %s</source> @@ -3623,7 +4473,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">Error: no se puede extraer el destino del scriptpubkey generado</translation> + <translation type="unfinished">Error: No se puede extraer el destino del scriptpubkey generado</translation> </message> <message> <source>Error: Couldn't create cursor into database</source> @@ -3643,11 +4493,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió una clave que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió una clave que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió un valor que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió un valor que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> @@ -3667,15 +4517,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: This wallet is already a descriptor wallet</source> - <translation type="unfinished">Error: Esta billetera ya es de descriptores</translation> + <translation type="unfinished">Error: Esta billetera ya está basada en descriptores</translation> </message> <message> <source>Error: Unable to begin reading all records in the database</source> - <translation type="unfinished">Error: No se puede comenzar a leer todos los registros en la base de datos</translation> + <translation type="unfinished">Error: No se pueden 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 se puede realizar una copia de seguridad de tu billetera</translation> + <translation type="unfinished">Error: No se puede realizar una copia de seguridad de la billetera</translation> </message> <message> <source>Error: Unable to parse version %u as a uint32_t</source> @@ -3687,7 +4537,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Error: no es capaz de leer el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo leer el registro del mejor localizador de bloques de la billetera.</translation> </message> <message> <source>Error: Unable to remove watchonly address book data</source> @@ -3699,28 +4549,31 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solucionable.</translation> </message> <message> <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor monedero vigilado del bloque del registro localizador</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solo de observación.</translation> </message> <message> <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera 1%s - </translation> + <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera %s</translation> </message> <message> <source>Error: database transaction cannot be executed for wallet %s</source> <translation type="unfinished">Error: la transacción de la base de datos no se puede ejecutar para la billetera %s</translation> </message> <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation type="unfinished">Fallo al escuchar en todos los puertos. Usa -listen=0 si quieres hacerlo.</translation> + </message> + <message> <source>Failed to rescan the wallet during initialization</source> <translation type="unfinished">Fallo al rescanear la billetera durante la inicialización</translation> </message> <message> <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Es erróneo al iniciar indizados, se apaga...</translation> + <translation type="unfinished">Error al iniciar Ãndices, cerrando...</translation> </message> <message> <source>Failed to verify database</source> @@ -3728,7 +4581,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failure removing transaction: %s</source> - <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> + <translation type="unfinished">Error al eliminar la transacción: %s</translation> </message> <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> @@ -3744,27 +4597,35 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">Incorrecto o bloque de génesis no encontrado. ¿datadir equivocada para la red?</translation> + <translation type="unfinished">El bloque génesis es incorrecto o no se encontró. ¿El directorio de datos es equivocado para la red?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation type="unfinished">Fallo al inicializar la comprobación de estado. %s se cerrará.</translation> </message> <message> <source>Input not found or already spent</source> - <translation type="unfinished">No se encontró o ya se gastó la entrada</translation> + <translation type="unfinished">La entrada no se encontró o ya se gastó</translation> </message> <message> <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">dbcache insuficiente para la verificación de bloques</translation> + <translation type="unfinished">Dbcache insuficiente para la verificación de bloques</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation type="unfinished">Fondos insuficientes</translation> </message> <message> <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">La dirección -i2psam o el nombre de host no es válido: "%s" </translation> + <translation type="unfinished">Dirección o nombre de host de -i2psam inválido: "%s" </translation> </message> <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -onion o dominio '%s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -onion inválido: "%s"</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -proxy o dominio ' %s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -proxy inválido: "%s"</translation> </message> <message> <source>Invalid P2P permission: '%s'</source> @@ -3779,16 +4640,24 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Importe inválido para %s=<amount>: "%s"</translation> </message> <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation type="unfinished">Importe inválido para -%s=<amount>: "%s"</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation type="unfinished">Máscara de red inválida especificada en -whitelist: "%s"</translation> + </message> + <message> <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Puerto no válido especificado en%s: '%s'</translation> + <translation type="unfinished">Puerto no válido especificado en %s: "%s"</translation> </message> <message> <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no válida %s</translation> + <translation type="unfinished">La entrada preseleccionada no es válida %s</translation> </message> <message> <source>Listening for incoming connections failed (listen returned error %s)</source> - <translation type="unfinished">Fallo en la escucha para conexiones entrantes (la escucha devolvió el error %s)</translation> + <translation type="unfinished">Fallo al escuchar conexiones entrantes (la escucha devolvió el error %s)</translation> </message> <message> <source>Loading P2P addresses…</source> @@ -3796,7 +4665,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Loading banlist…</source> - <translation type="unfinished">Cargando lista de bloqueos...</translation> + <translation type="unfinished">Cargando lista de prohibiciones...</translation> </message> <message> <source>Loading block index…</source> @@ -3808,23 +4677,31 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Missing amount</source> - <translation type="unfinished">Falta la cantidad</translation> + <translation type="unfinished">Falta el importe</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 la transacción</translation> </message> <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation type="unfinished">Se necesita especificar un puerto con -whitebind: "%s"</translation> + </message> + <message> <source>No addresses available</source> <translation type="unfinished">No hay direcciones disponibles</translation> </message> <message> + <source>Not enough file descriptors available.</source> + <translation type="unfinished">No hay suficientes descriptores de archivo disponibles.</translation> + </message> + <message> <source>Not found pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no encontrada%s</translation> + <translation type="unfinished">La entrada preseleccionada no se encontró %s</translation> </message> <message> <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no solucionable %s</translation> + <translation type="unfinished">La entrada preseleccionada no se puede solucionar %s</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -3836,7 +4713,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Pruning blockstore…</source> - <translation type="unfinished">Podando almacén de bloques…</translation> + <translation type="unfinished">Podando almacenamiento 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> @@ -3868,7 +4749,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished">Firma de transacción fallida</translation> + <translation type="unfinished">Fallo al firmar la transacción</translation> </message> <message> <source>Specified -walletdir "%s" does not exist</source> @@ -3896,7 +4777,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The source code is available from %s.</source> - <translation type="unfinished">El código fuente esta disponible desde %s.</translation> + <translation type="unfinished">El código fuente está disponible en %s.</translation> </message> <message> <source>The specified config file %s does not exist</source> @@ -3904,15 +4785,23 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">El monto de la transacción es demasiado pequeño para pagar la comisión</translation> + <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">La billetera evitará pagar menos que 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">MÃnimo de impuesto que pagarás con cada transacción.</translation> + <translation type="unfinished">Esta es la comisión mÃnima de transacción que pagas 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> + <translation type="unfinished">Esta es la comisión de transacción que pagarás si envÃas una transacción.</translation> </message> <message> <source>Transaction %s does not belong to this wallet</source> @@ -3924,7 +4813,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Los montos de la transacción no debe ser negativo</translation> + <translation type="unfinished">Los importes de la transacción no pueden ser negativos</translation> </message> <message> <source>Transaction change output index out of range</source> @@ -3932,7 +4821,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction must have at least one recipient</source> - <translation type="unfinished">La transacción debe tener al menos un destinatario</translation> + <translation type="unfinished">La transacción debe incluir al menos un destinatario</translation> </message> <message> <source>Transaction needs a change address, but we can't generate it.</source> @@ -3979,6 +4868,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">No se puede analizar -maxuploadtarget: "%s"</translation> </message> <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation type="unfinished">No se puede iniciar el servidor HTTP. Consulta el registro de depuración para obtener información.</translation> + </message> + <message> <source>Unable to unload the wallet before migrating</source> <translation type="unfinished">No se puede descargar la billetera antes de la migración</translation> </message> @@ -3996,7 +4889,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">La red especificada en -onlynet '%s' es desconocida</translation> + <translation type="unfinished">Se desconoce la red especificada en -onlynet: "%s"</translation> </message> <message> <source>Unknown new rules activated (versionbit %i)</source> @@ -4004,15 +4897,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Nivel de acceso global %s = %s no mantenido. Los valores válidos son: %s.</translation> + <translation type="unfinished">El nivel de registro global %s=%s no es compatible. Valores válidos: %s.</translation> </message> <message> <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Creación errónea del fichero monedero: %s</translation> + <translation type="unfinished">Error al crear el archivo de la billetera: %s</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates no está mantenido en el encadenamiento %s.</translation> + <translation type="unfinished">acceptstalefeeestimates no se admite en la cadena %s.</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> @@ -4020,11 +4913,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Error: no pudo agregar tx de solo vigÃa %s para monedero de solo vigÃa</translation> + <translation type="unfinished">Error: No se pudo agregar la transacción %s a la billetera solo de observación.</translation> </message> <message> <source>Error: Could not delete watchonly transactions. </source> - <translation type="unfinished">Error: no se pudieron eliminar las transacciones de watchonly.</translation> + <translation type="unfinished">Error: No se pudieron eliminar las transacciones solo de observación</translation> </message> <message> <source>User Agent comment (%s) contains unsafe characters.</source> @@ -4044,7 +4937,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Settings file could not be read</source> - <translation type="unfinished">El archivo de configuración no puede leerse</translation> + <translation type="unfinished">El archivo de configuración no se puede leer</translation> </message> <message> <source>Settings file could not be written</source> diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts index 139fc7b42e..681cd65b41 100644 --- a/src/qt/locale/bitcoin_es_VE.ts +++ b/src/qt/locale/bitcoin_es_VE.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation type="unfinished">Haga clic con el botón derecho para editar una dirección o etiqueta</translation> + <translation type="unfinished">Hacer clic derecho para editar la dirección o etiqueta</translation> </message> <message> <source>Create a new address</source> @@ -11,11 +11,11 @@ </message> <message> <source>&New</source> - <translation type="unfinished">&Nuevo</translation> + <translation type="unfinished">&Nueva</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation type="unfinished">Copiar la dirección seleccionada al portapapeles del sistema</translation> + <translation type="unfinished">Copiar la dirección seleccionada actualmente al portapapeles del sistema</translation> </message> <message> <source>&Copy</source> @@ -27,15 +27,15 @@ </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 la dirección seleccionada de la lista</translation> </message> <message> <source>Enter address or label to search</source> - <translation type="unfinished">Introduzca una dirección o etiqueta que buscar</translation> + <translation type="unfinished">Ingresar una dirección o etiqueta para buscar</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar a un archivo los datos de esta pestaña</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> <source>&Export</source> @@ -43,37 +43,37 @@ </message> <message> <source>&Delete</source> - <translation type="unfinished">&Eliminar</translation> + <translation type="unfinished">&Borrar</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished">Escoja la dirección a la que se enviarán monedas</translation> + <translation type="unfinished">Elige la dirección a la que se enviarán monedas</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation type="unfinished">Escoja la dirección donde quiere recibir monedas</translation> + <translation type="unfinished">Elige la dirección con la que se recibirán monedas</translation> </message> <message> <source>C&hoose</source> - <translation type="unfinished">Escoger</translation> + <translation type="unfinished">&Seleccionar</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">Estas son sus direcciones Bitcoin para enviar pagos. Compruebe siempre la cantidad y la dirección de recibo antes de transferir monedas.</translation> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para enviar pagos. Revisa siempre el importe 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">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> + <translation type="unfinished">Estas son tus direcciones de Bitcoin para recibir pagos. Usa el botón "Crear nueva dirección de recepción" en la pestaña "Recibir" para crear nuevas direcciones. +Solo es posible firmar con direcciones de tipo legacy.</translation> </message> <message> <source>&Copy Address</source> - <translation type="unfinished">Copiar dirección</translation> + <translation type="unfinished">&Copiar dirección</translation> </message> <message> <source>Copy &Label</source> - <translation type="unfinished">Copiar &Etiqueta</translation> + <translation type="unfinished">Copiar &etiqueta</translation> </message> <message> <source>&Edit</source> @@ -81,7 +81,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Export Address List</source> - <translation type="unfinished">Exportar la Lista de Direcciones</translation> + <translation type="unfinished">Exportar lista de direcciones</translation> </message> <message> <source>Comma separated file</source> @@ -91,7 +91,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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">Hubo un error al intentar guardar la lista de direcciones a %1. Por favor trate de nuevo.</translation> + <translation type="unfinished">Ocurrió un error al intentar guardar la lista de direcciones en %1. Inténtalo de nuevo.</translation> </message> <message> <source>Sending addresses - %1</source> @@ -103,7 +103,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Exporting Failed</source> - <translation type="unfinished">La exportación falló</translation> + <translation type="unfinished">Error al exportar</translation> </message> </context> <context> @@ -125,19 +125,19 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation type="unfinished">Diálogo de contraseña</translation> + <translation type="unfinished">Diálogo de frase de contraseña</translation> </message> <message> <source>Enter passphrase</source> - <translation type="unfinished">Introducir contraseña</translation> + <translation type="unfinished">Ingresar la frase de contraseña</translation> </message> <message> <source>New passphrase</source> - <translation type="unfinished">Nueva contraseña</translation> + <translation type="unfinished">Nueva frase de contraseña</translation> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Repita la nueva contraseña</translation> + <translation type="unfinished">Repetir la nueva frase de contraseña</translation> </message> <message> <source>Show passphrase</source> @@ -145,35 +145,35 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Encrypt wallet</source> - <translation type="unfinished">Cifrar monedero</translation> + <translation type="unfinished">Encriptar billetera</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Esta operación requiere su contraseña para desbloquear el monedero.</translation> + <translation type="unfinished">Esta operación requiere la frase de contraseña de la billetera para desbloquearla.</translation> </message> <message> <source>Unlock wallet</source> - <translation type="unfinished">Desbloquear monedero</translation> + <translation type="unfinished">Desbloquear billetera</translation> </message> <message> <source>Change passphrase</source> - <translation type="unfinished">Cambiar frase secreta</translation> + <translation type="unfinished">Cambiar frase de contraseña</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation type="unfinished">Confirme cifrado del monedero</translation> + <translation type="unfinished">Confirmar el encriptado de la billetera</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> - <translation type="unfinished">Atención: Si cifra su monedero y pierde la contraseña, perderá ¡<b>TODOS SUS BITCOINS</b>!</translation> + <translation type="unfinished">Advertencia: Si encriptas la billetera y pierdes tu frase de contraseña, ¡<b>PERDERÃS TODOS TUS BITCOINS</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation type="unfinished">¿Está seguro que desea cifrar su monedero?</translation> + <translation type="unfinished">¿Seguro quieres encriptar la billetera?</translation> </message> <message> <source>Wallet encrypted</source> - <translation type="unfinished">Monedero cifrado</translation> + <translation type="unfinished">Billetera encriptada</translation> </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> @@ -181,47 +181,47 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation type="unfinished">Introduce la contraseña antigua y la nueva para el monedero.</translation> + <translation type="unfinished">Ingresa la antigua frase de contraseña 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 garantiza total protección de robo de tus bitcoins si tu ordenador es infectado con malware.</translation> + <translation type="unfinished">Recuerda que encriptar tu billetera no garantiza la protección total contra el robo de tus bitcoins si la computadora está infectada con malware.</translation> </message> <message> <source>Wallet to be encrypted</source> - <translation type="unfinished">Billetera a ser cifrada</translation> + <translation type="unfinished">Billetera para encriptar</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> - <translation type="unfinished">Tu billetera esta por ser encriptada</translation> + <translation type="unfinished">Tu billetera está a punto de encriptarse.</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation type="unfinished">Su billetera está ahora cifrada</translation> + <translation type="unfinished">Tu billetera ahora está encriptada.</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: Algunas copias de seguridad que hayas hecho de tu archivo de billetera deberÃan ser reemplazadas con la billetera encriptada generada recientemente. Por razones de seguridad, las copias de seguridad previas del archivo de billetera sin cifrar serán inútiles tan pronto uses la nueva billetera encriptada.</translation> + <translation type="unfinished">IMPORTANTE: Cualquier copia de seguridad anterior que hayas hecho del archivo de la billetera se deberá reemplazar por el nuevo archivo encriptado que generaste. Por motivos de seguridad, las copias de seguridad realizadas anteriormente quedarán obsoletas en cuanto empieces a usar la nueva billetera encriptada.</translation> </message> <message> <source>Wallet encryption failed</source> - <translation type="unfinished">Encriptado de monedero fallido</translation> + <translation type="unfinished">Falló el encriptado de la billetera</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation type="unfinished">Encriptación de billetera fallida debido a un error interno. Tu billetera no fue encriptada.</translation> + <translation type="unfinished">El encriptado de la billetera falló debido a un error interno. La billetera no se encriptó.</translation> </message> <message> <source>The supplied passphrases do not match.</source> - <translation type="unfinished">Las frases secretas introducidas no concuerdan.</translation> + <translation type="unfinished">Las frases de contraseña proporcionadas no coinciden.</translation> </message> <message> <source>Wallet unlock failed</source> - <translation type="unfinished">Desbloqueo de billetera fallido</translation> + <translation type="unfinished">Falló el desbloqueo de la billetera</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation type="unfinished">La frase secreta introducida para la desencriptación de la billetera fué incorrecta.</translation> + <translation type="unfinished">La frase de contraseña introducida para el cifrado de la billetera es incorrecta.</translation> </message> <message> <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> @@ -229,7 +229,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation type="unfinished">La frase secreta de la billetera fué cambiada exitosamente.</translation> + <translation type="unfinished">La frase de contraseña de la billetera se cambió correctamente.</translation> </message> <message> <source>Passphrase change failed</source> @@ -241,14 +241,18 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">Aviso: El bloqueo de mayúsculas está activado.</translation> + <translation type="unfinished">Advertencia: ¡Las mayúsculas están activadas!</translation> </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">Bloqueado hasta</translation> + <translation type="unfinished">Prohibido hasta</translation> </message> </context> <context> @@ -258,8 +262,12 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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 ha producido un error garrafal. %1Ya no podrá continuar de manera segura y abandonará.</translation> + <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> @@ -267,7 +275,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</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">Un error interno ocurrió. %1 intentará continuar. Este es un error inesperado que puede ser reportado de las formas que se muestran debajo,</translation> + <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> @@ -280,7 +288,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</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 ejecutar de nuevo el programa con -nosettings</translation> + <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>%1 didn't yet exit safely…</source> @@ -291,6 +299,10 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <translation type="unfinished">desconocido</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">"%1" integrado</translation> + </message> + <message> <source>Default system font "%1"</source> <translation type="unfinished">Fuente predeterminada del sistema "%1"</translation> </message> @@ -300,11 +312,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</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> - <translation type="unfinished">Ingresa una dirección de Bitcoin (Ejemplo: %1)</translation> + <translation type="unfinished">Ingresar una dirección de Bitcoin (por ejemplo, %1)</translation> </message> <message> <source>Unroutable</source> @@ -318,7 +330,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <message> <source>Outbound</source> <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> <message> <source>Full Relay</source> @@ -328,7 +340,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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> + <translation type="unfinished">Retransmisión de bloques</translation> </message> <message> <source>Address Fetch</source> @@ -398,7 +410,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Show general overview of wallet</source> - <translation type="unfinished">Mostrar vista general del monedero</translation> + <translation type="unfinished">Muestra una vista general de la billetera</translation> </message> <message> <source>&Transactions</source> @@ -406,7 +418,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Browse transaction history</source> - <translation type="unfinished">Examinar el historial de transacciones</translation> + <translation type="unfinished">Explora el historial de transacciones</translation> </message> <message> <source>E&xit</source> @@ -414,7 +426,15 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Quit application</source> - <translation type="unfinished">Salir de la aplicación</translation> + <translation type="unfinished">Salir del programa</translation> + </message> + <message> + <source>&About %1</source> + <translation type="unfinished">&Acerca de %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation type="unfinished">Mostrar Información sobre %1</translation> </message> <message> <source>About &Qt</source> @@ -422,7 +442,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Show information about Qt</source> - <translation type="unfinished">Mostrar información acerca de Qt</translation> + <translation type="unfinished">Mostrar información sobre Qt</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation type="unfinished">Modificar las opciones de configuración para %1</translation> </message> <message> <source>Create a new wallet</source> @@ -433,21 +457,29 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <translation type="unfinished">&Minimizar</translation> </message> <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> <source>Network activity disabled.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished">Actividad de red deshabilitada.</translation> </message> <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation type="unfinished">Proxy <b>habilitado</b>: %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> - <translation type="unfinished">Enviar monedas a una dirección Bitcoin</translation> + <translation type="unfinished">Enviar monedas a una dirección de Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Copia de seguridad del monedero en otra ubicación</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera 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> + <translation type="unfinished">Cambiar la frase de contraseña utilizada para encriptar la billetera</translation> </message> <message> <source>&Send</source> @@ -458,28 +490,44 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <translation type="unfinished">&Recibir</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Opciones…</translation> + </message> + <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">&Cifrar monedero</translation> + <translation type="unfinished">&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">Encriptar las claves privadas que pertenecen a la billetera</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Realizar copia de seguridad de la billetera...</translation> </message> <message> <source>&Change Passphrase…</source> <translation type="unfinished">&Cambiar frase de contraseña...</translation> </message> <message> + <source>Sign &message…</source> + <translation type="unfinished">Firmar &mensaje...</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation type="unfinished">Firmar mensajes con sus direcciones Bitcoin para demostrar la propiedad</translation> + <translation type="unfinished">Firmar mensajes con tus direcciones de Bitcoin para demostrar que te pertenecen</translation> + </message> + <message> + <source>&Verify message…</source> + <translation type="unfinished">&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> + <translation type="unfinished">Verificar mensajes para asegurarte de que estén firmados con direcciones de Bitcoin concretas</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Cargar PSBT desde archivo...</translation> + <translation type="unfinished">&Cargar TBPF desde archivo...</translation> </message> <message> <source>Open &URI…</source> @@ -487,15 +535,15 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Close Wallet…</source> - <translation type="unfinished">Cerrar monedero...</translation> + <translation type="unfinished">Cerrar billetera...</translation> </message> <message> <source>Create Wallet…</source> - <translation type="unfinished">Crear monedero...</translation> + <translation type="unfinished">Crear billetera...</translation> </message> <message> <source>Close All Wallets…</source> - <translation type="unfinished">Cerrar todos los monederos...</translation> + <translation type="unfinished">Cerrar todas las billeteras...</translation> </message> <message> <source>&File</source> @@ -507,7 +555,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>&Help</source> - <translation type="unfinished">A&yuda</translation> + <translation type="unfinished">&Ayuda</translation> </message> <message> <source>Tabs toolbar</source> @@ -535,25 +583,25 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Solicitar pagos (genera codigo QR y URL's de Bitcoin)</translation> + <translation type="unfinished">Solicitar pagos (genera códigos QR y URI de tipo "bitcoin:")</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation type="unfinished">Mostrar la lista de direcciones de envÃo y etiquetas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de envÃo usadas</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation type="unfinished">Muestra la lista de direcciones de recepción y etiquetas</translation> + <translation type="unfinished">Mostrar la lista de etiquetas y direcciones de recepción usadas</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">&Opciones de linea de comando</translation> + <translation type="unfinished">&Opciones de lÃnea de comandos</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform>%n bloque procesado del historial de transacciones.</numerusform> - <numerusform>%n bloques procesados del historial de transacciones.</numerusform> + <numerusform>Se procesó %n bloque del historial de transacciones.</numerusform> + <numerusform>Se procesaron %n bloques del historial de transacciones.</numerusform> </translation> </message> <message> @@ -566,7 +614,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation type="unfinished">El último bloque recibido fue generado hace %1.</translation> + <translation type="unfinished">El último bloque recibido se generó hace %1.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> @@ -574,7 +622,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Warning</source> - <translation type="unfinished">Aviso</translation> + <translation type="unfinished">Advertencia</translation> </message> <message> <source>Information</source> @@ -590,7 +638,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Cargar PSBT desde el &portapapeles...</translation> + <translation type="unfinished">Cargar TBPF desde el &portapapeles...</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> @@ -598,11 +646,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Abrir consola de depuración y diagnóstico de nodo</translation> + <translation type="unfinished">Abrir la consola de depuración y diagnóstico del nodo</translation> </message> <message> <source>&Sending addresses</source> @@ -610,19 +658,23 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Direcciones de recepción</translation> + <translation type="unfinished">&Direcciones de destino</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Bitcoin: abrir URI</translation> + <translation type="unfinished">Abrir un URI de tipo "bitcoin:"</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Abrir monedero</translation> + <translation type="unfinished">Abrir billetera</translation> + </message> + <message> + <source>Open a wallet</source> + <translation type="unfinished">Abrir una billetera</translation> </message> <message> <source>Close wallet</source> - <translation type="unfinished">Cerrar monedero</translation> + <translation type="unfinished">Cerrar billetera</translation> </message> <message> <source>Restore Wallet…</source> @@ -636,7 +688,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Migrate Wallet</source> @@ -647,20 +699,24 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <translation type="unfinished">Migrar una billetera</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation type="unfinished">Mostrar el mensaje de ayuda %1 para obtener una lista de las posibles opciones de lÃnea de comandos de Bitcoin</translation> + </message> + <message> <source>&Mask values</source> <translation type="unfinished">&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> + <translation type="unfinished">Ocultar los valores en la pestaña "Vista general"</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> <message> <source>No wallets available</source> - <translation type="unfinished">Monederos no disponibles</translation> + <translation type="unfinished">No hay billeteras disponibles</translation> </message> <message> <source>Wallet Data</source> @@ -680,13 +736,21 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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> + <translation type="unfinished">Nombre de la billetera</translation> </message> <message> <source>&Window</source> <translation type="unfinished">&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> @@ -696,14 +760,14 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>S&how</source> - <translation type="unfinished">M&ostrar</translation> + <translation type="unfinished">&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>%n conexiones activas con la red Bitcoin</numerusform> - <numerusform>%n conexiones activas con la red Bitcoin </numerusform> + <numerusform>%n conexión activa con la red de Bitcoin.</numerusform> + <numerusform>%n conexiones activas con la red de Bitcoin.</numerusform> </translation> </message> <message> @@ -736,7 +800,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> - <translation type="unfinished">No se puede crear una nueva billetera, el software se compiló sin soporte sqlite (requerido para billeteras descriptivas)</translation> + <translation type="unfinished">No se puede crear una billetera nueva, ya que el software se compiló sin compatibilidad con sqlite (requerida para billeteras basadas en descriptores)</translation> </message> <message> <source>Warning: %1</source> @@ -769,7 +833,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <message> <source>Label: %1 </source> - <translation type="unfinished">Etiqueta: %1 + <translation type="unfinished">Etiqueta %1 </translation> </message> <message> @@ -792,7 +856,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">La generación de la clave HD está <b> desactivada</b></translation> + <translation type="unfinished">La generación de clave HD está <b>deshabilitada</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -800,11 +864,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation type="unfinished">El monedero está <b>cifrado</b> y actualmente <b>desbloqueado</b></translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>desbloqueda</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation type="unfinished">El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b></translation> + <translation type="unfinished">La billetera está <b>encriptada</b> y actualmente <b>bloqueda</b></translation> </message> <message> <source>Original message:</source> @@ -815,14 +879,14 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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 las cantidades. Haga clic para seleccionar otra unidad.</translation> + <translation type="unfinished">Unidad en la que se muestran los importes. Haz clic para seleccionar otra unidad.</translation> </message> </context> <context> <name>CoinControlDialog</name> <message> <source>Coin Selection</source> - <translation type="unfinished">Selección de moneda</translation> + <translation type="unfinished">Selección de monedas</translation> </message> <message> <source>Quantity:</source> @@ -830,15 +894,15 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</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">Tasa:</translation> + <translation type="unfinished">Comisión:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Después de tasas:</translation> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> <source>Change:</source> @@ -846,11 +910,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>(un)select all</source> - <translation type="unfinished">(des)selecciona todos</translation> + <translation type="unfinished">(des)marcar todos</translation> </message> <message> <source>Tree mode</source> - <translation type="unfinished">Modo arbol</translation> + <translation type="unfinished">Modo árbol</translation> </message> <message> <source>List mode</source> @@ -858,7 +922,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Amount</source> - <translation type="unfinished">Cantidad</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>Received with label</source> @@ -878,11 +942,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmado</translation> + <translation type="unfinished">Confirmada</translation> </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>&Copy address</source> @@ -902,7 +966,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>L&ock unspent</source> - <translation type="unfinished">B&loquear importe no gastado</translation> + <translation type="unfinished">&Bloquear importe no gastado</translation> </message> <message> <source>&Unlock unspent</source> @@ -918,7 +982,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de la tarifa</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -942,7 +1006,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>change from %1 (%2)</source> - <translation type="unfinished">Cambio desde %1 (%2)</translation> + <translation type="unfinished">cambio desde %1 (%2)</translation> </message> <message> <source>(change)</source> @@ -952,6 +1016,11 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <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">Crear billetera</translation> + </message> + <message> <source>Creating Wallet <b>%1</b>…</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 billetera <b>%1</b>…</translation> @@ -962,7 +1031,7 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> </message> <message> <source>Create wallet warning</source> - <translation type="unfinished">Advertencia de crear billetera</translation> + <translation type="unfinished">Advertencia al crear la billetera</translation> </message> <message> <source>Can't list signers</source> @@ -978,12 +1047,12 @@ Registrarse solo es posible utilizando una direccion tipo "Legal"</translation> <message> <source>Load Wallets</source> <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment> - <translation type="unfinished">Cargar monederos</translation> + <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 monederos...</translation> + <translation type="unfinished">Cargando billeteras...</translation> </message> </context> <context> @@ -1003,10 +1072,10 @@ If this wallet contains any solvable but not watched scripts, a different and ne The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> <translation type="unfinished">La migración de la billetera la convertirá en una o más billeteras basadas en descriptores. Será necesario realizar una nueva copia de seguridad de la billetera. -Si esta billetera contiene scripts solo de lectura, se creará una nueva billetera que los contenga. -Si esta billetera contiene scripts solucionables pero no de lectura, se creará una nueva billetera diferente que los contenga. +Si esta billetera contiene scripts solo de observación, se creará una nueva billetera que los contenga. +Si esta billetera contiene scripts solucionables pero no de observación, se creará una nueva billetera diferente que los contenga. -El proceso de migración creará una copia de seguridad de la billetera antes de migrar. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En el caso de una migración incorrecta, la copia de seguridad puede restaurarse con la funcionalidad "Restore Wallet" (Restaurar billetera).</translation> +El proceso de migración creará una copia de seguridad de la billetera antes de proceder. Este archivo de copia de seguridad se llamará <wallet name>-<timestamp>.legacy.bak y se encontrará en el directorio de esta billetera. En caso de que la migración falle, se puede restaurar la copia de seguridad con la funcionalidad "Restaurar billetera".</translation> </message> <message> <source>Migrate Wallet</source> @@ -1022,11 +1091,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Guiones vigilantes han sido migrados a un monedero con el nombre '%1'.</translation> + <translation type="unfinished">Los scripts solo de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Solucionable pero ninguno de los guiones vigilados han sido migrados a un monedero llamados '%1'.</translation> + <translation type="unfinished">Los scripts solucionables pero no de observación se migraron a una nueva billetera llamada "%1".</translation> </message> <message> <source>Migration failed</source> @@ -1040,22 +1109,26 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 sobre crear monedero</translation> + <translation type="unfinished">Advertencia al abrir billetera</translation> </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</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 billetera</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</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 <b>%1</b>...</translation> + <translation type="unfinished">Abriendo billetera <b>%1</b>...</translation> </message> </context> <context> @@ -1090,46 +1163,62 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <name>WalletController</name> <message> <source>Close wallet</source> - <translation type="unfinished">Cerrar monedero</translation> + <translation type="unfinished">Cerrar billetera</translation> </message> <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">¿Estás seguro de que deseas cerrar el monedero <i>%1</i>?</translation> + <translation type="unfinished">¿Seguro deseas cerrar la billetera <i>%1</i>?</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> + <translation type="unfinished">Cerrar la billetera durante demasiado tiempo puede causar la resincronización de toda la cadena si el podado está habilitado.</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Cerrar todos los monederos</translation> + <translation type="unfinished">Cerrar todas las billeteras</translation> </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">¿Está seguro de que desea cerrar todas las billeteras?</translation> + <translation type="unfinished">¿Seguro quieres cerrar todas las billeteras?</translation> </message> </context> <context> <name>CreateWalletDialog</name> <message> + <source>Create Wallet</source> + <translation type="unfinished">Crear billetera</translation> + </message> + <message> <source>You are one step away from creating your new wallet!</source> <translation type="unfinished">Estás a un paso de crear tu nueva billetera.</translation> </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Escribe un nombre y, si lo deseas, activa las opciones avanzadas.</translation> + <translation type="unfinished">Escribe un nombre y, si quieres, activa las opciones avanzadas.</translation> </message> <message> <source>Wallet Name</source> - <translation type="unfinished">Nombre del monedero</translation> + <translation type="unfinished">Nombre de la billetera </translation> </message> <message> <source>Wallet</source> - <translation type="unfinished">Monedero</translation> + <translation type="unfinished">Billetera</translation> </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">Encriptar la billetera. La billetera será encriptada con una contraseña de tu elección.</translation> + <translation type="unfinished">Encriptar la billetera. La billetera se encriptará con una frase de contraseña de tu elección.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation type="unfinished">Encriptar billetera</translation> + </message> + <message> + <source>Advanced Options</source> + <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">Desactivar las claves privadas para esta billetera. Las billeteras con claves privadas desactivadas no tendrán claves privadas y no podrán tener ninguna semilla HD ni claves privadas importadas. Esto es ideal para billeteras solo de observación.</translation> </message> <message> <source>Disable Private Keys</source> @@ -1137,11 +1226,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Crea una billetera en blanco. Las billeteras en blanco inicialmente no tienen llaves privadas ni scripts. Las llaves privadas y las direcciones pueden ser importadas o se puede establecer una semilla HD más tarde.</translation> </message> <message> <source>Make Blank Wallet</source> - <translation type="unfinished">Crear billetera vacÃa</translation> + <translation type="unfinished">Crear billetera en blanco</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">Usa un dispositivo de firma externo, por ejemplo, una billetera de hardware. Configura primero el script del firmante externo en las preferencias de la billetera.</translation> </message> <message> <source>External signer</source> @@ -1154,14 +1247,14 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> </context> <context> <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>&Label</source> @@ -1169,11 +1262,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished">La etiqueta asociada con esta entrada de la lista de direcciones</translation> + <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 de la lista de direcciones. Solo puede ser modificada para direcciones de envÃo.</translation> + <translation type="unfinished">La dirección asociada con esta entrada en la lista de direcciones. Solo se puede modificar para las direcciones de envÃo.</translation> </message> <message> <source>&Address</source> @@ -1185,7 +1278,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Edit receiving address</source> - <translation type="unfinished">Editar dirección de envÃo</translation> + <translation type="unfinished">Editar dirección de recepción</translation> </message> <message> <source>Edit sending address</source> @@ -1193,7 +1286,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">La dirección ingresada "%1" no es una dirección de 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 ingresada "%1" ya está en la libreta de direcciones con la etiqueta "%2".</translation> </message> <message> <source>Could not unlock wallet.</source> @@ -1201,7 +1302,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>New key generation failed.</source> - <translation type="unfinished">Creación de la nueva llave fallida</translation> + <translation type="unfinished">Error al generar clave nueva.</translation> </message> </context> <context> @@ -1216,11 +1317,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation type="unfinished">El directorio ya existe. Añada %1 si pretende crear aquà un directorio nuevo.</translation> + <translation type="unfinished">El directorio ya existe. Agrega %1 si deseas 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> + <translation type="unfinished">Ruta de acceso existente, pero no es un directorio.</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -1239,15 +1340,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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>(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 needed for full chain)</numerusform> - <numerusform>(%n GB needed for full chain)</numerusform> + <numerusform>(%n GB necesario para completar la cadena)</numerusform> + <numerusform>(%n GB necesarios para completar la cadena)</numerusform> </translation> </message> <message> @@ -1255,8 +1356,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Elegir directorio de datos</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">Se almacenará al menos %1 GB de información en este directorio, que aumentará con el tiempo.</translation> + </message> + <message> <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> + <translation type="unfinished">Se almacenará aproximadamente %1 GB de información en este directorio.</translation> </message> <message numerus="yes"> <source>(sufficient to restore backups %n day(s) old)</source> @@ -1272,27 +1377,35 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">La billetera también se almacenará en este directorio.</translation> </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">Error: Directorio de datos especificado "%1" no puede ser creado.</translation> + <translation type="unfinished">Error: No se puede crear el directorio de datos especificado "%1" .</translation> </message> <message> <source>Welcome</source> - <translation type="unfinished">Bienvenido</translation> + <translation type="unfinished">Te damos la bienvenida</translation> </message> <message> <source>Welcome to %1.</source> - <translation type="unfinished">Bienvenido a %1.</translation> + <translation type="unfinished">Te damos la bienvenida 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> + <translation type="unfinished">Como es la primera vez que se ejecuta el programa, puedes elegir dónde %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> + <translation type="unfinished">Limitar el almacenamiento de la 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">Para revertir esta configuración, se debe descargar de nuevo la cadena de bloques completa. Es más rápido descargar la cadena completa y podarla después. Desactiva algunas funciones avanzadas.</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">La sincronización inicial consume muchos recursos y es posible que exponga problemas de hardware en la computadora que anteriormente pasaron desapercibidos. Cada vez que ejecutes %1, seguirá descargando desde el punto en el que quedó.</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> @@ -1300,15 +1413,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Si elegiste la opción de limitar el almacenamiento de la cadena de bloques (podado), los datos históricos se deben descargar y procesar de igual manera, pero se eliminarán después para disminuir el uso del disco.</translation> </message> <message> <source>Use the default data directory</source> - <translation type="unfinished">Utilizar el directorio de datos predeterminado</translation> + <translation type="unfinished">Usar el directorio de datos predeterminado</translation> </message> <message> <source>Use a custom data directory:</source> - <translation type="unfinished">Utilice un directorio de datos personalizado:</translation> + <translation type="unfinished">Usar un directorio de datos personalizado:</translation> </message> </context> <context> @@ -1323,42 +1436,73 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Command-line options</source> - <translation type="unfinished">Opciones de la lÃnea de órdenes</translation> + <translation type="unfinished">Opciones de lÃnea de comandos</translation> + </message> +</context> +<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 apagues la computadora hasta que desaparezca esta ventana.</translation> </message> </context> <context> <name>ModalOverlay</name> <message> <source>Form</source> - <translation type="unfinished">Desde</translation> + <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> + <translation type="unfinished">Es posible que las transacciones recientes aún no sean visibles y, por lo tanto, el saldo de la billetera podrÃa ser incorrecto. Esta información será correcta una vez que la billetera haya terminado de sincronizarse con la red de Bitcoin, como se detalla abajo.</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á si se intenta gastar bitcoins afectados por las transacciones que aún no se muestran.</translation> </message> <message> <source>Number of blocks left</source> - <translation type="unfinished">Numero de bloques pendientes</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> <message> + <source>Progress</source> + <translation type="unfinished">Progreso</translation> + </message> + <message> <source>Progress increase per hour</source> - <translation type="unfinished">Incremento del progreso por hora</translation> + <translation type="unfinished">Avance del progreso por hora</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation type="unfinished">Tiempo estimado restante hasta la sincronización</translation> + </message> + <message> + <source>Hide</source> + <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> + <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 cabeceras (%1, %2%)…</translation> + <translation type="unfinished">Desconocido. Sincronizando encabezados (%1, %2%)…</translation> </message> <message> <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> @@ -1374,7 +1518,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> </context> <context> @@ -1388,16 +1532,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">&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>&Start %1 on system login</source> - <translation type="unfinished">&Iniciar %1 al iniciar el sistema</translation> + <translation type="unfinished">&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">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> + <translation type="unfinished">Al activar el podado, 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 &database cache</source> + <translation type="unfinished">Tamaño de la caché de la &base de datos</translation> </message> <message> <source>Number of script &verification threads</source> - <translation type="unfinished">Número de hilos de &verificación de scripts</translation> + <translation type="unfinished">Número de subprocesos de &verificación de scripts</translation> </message> <message> <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> @@ -1405,15 +1557,19 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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 (ej. IPv4: 127.0.0.1 / IPv6: ::1)</translation> + <translation type="unfinished">Dirección IP del proxy (por 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 suministrado se utiliza para llegar a los 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">Minimice en lugar de salir de la aplicación cuando la ventana esté cerrada. Cuando esta opción está habilitada, la aplicación se cerrará solo después de seleccionar Salir en el menú.</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 solo se cerrará después de seleccionar "Salir" en el menú.</translation> </message> <message> <source>Font in the Overview tab: </source> - <translation type="unfinished">Fuente en la pestaña Resumen:</translation> + <translation type="unfinished">Fuente en la pestaña "Vista general":</translation> </message> <message> <source>Options set in this dialog are overridden by the command line:</source> @@ -1429,7 +1585,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Reset all client options to default.</source> - <translation type="unfinished">Restablecer todas las opciones del cliente a las predeterminadas.</translation> + <translation type="unfinished">Restablecer todas las opciones del cliente a los valores predeterminados.</translation> </message> <message> <source>&Reset Options</source> @@ -1455,7 +1611,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">Establece el número de subprocesos 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, <0 = leave that many cores free)</source> @@ -1464,7 +1620,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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 los comandos JSON-RPC.</translation> </message> <message> <source>Enable R&PC server</source> @@ -1473,12 +1629,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>W&allet</source> - <translation type="unfinished">Monedero</translation> + <translation type="unfinished">&Billetera</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> + <translation type="unfinished">Si se resta o no la comisión del importe por defecto.</translation> </message> <message> <source>Subtract &fee from amount by default</source> @@ -1490,8 +1646,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Experto</translation> </message> <message> + <source>Enable coin &control features</source> + <translation type="unfinished">Habilitar funciones de &control de monedas</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 deshabilita 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 cómo se calcula su saldo.</translation> + <translation type="unfinished">Si deshabilitas el gasto del cambio sin confirmar, no se puede usar el cambio de una transacción hasta que esta tenga al menos una confirmación. Esto también afecta cómo se calcula el saldo.</translation> </message> <message> <source>&Spend unconfirmed change</source> @@ -1500,12 +1660,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <message> <source>Enable &PSBT controls</source> <extracomment>An options window setting to enable PSBT controls.</extracomment> - <translation type="unfinished">Activar controles de &PSBT</translation> + <translation type="unfinished">Activar controles de &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">Si se muestran los controles de PSBT.</translation> + <translation type="unfinished">Si se muestran los controles de TBPF.</translation> </message> <message> <source>External Signer (e.g. hardware wallet)</source> @@ -1517,11 +1677,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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 si el router admite UPnP y está activado.</translation> + <translation type="unfinished">Abrir automáticamente el puerto del cliente de Bitcoin en el router. Esto funciona solo cuando tu router es compatible con UPnP y está habilitado.</translation> </message> <message> <source>Map port using &UPnP</source> - <translation type="unfinished">Mapear el puerto usando &UPnP</translation> + <translation type="unfinished">Asignar puerto usando &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> @@ -1532,16 +1692,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <translation type="unfinished">Asignar puerto usando NA&T-PMP</translation> </message> <message> + <source>Accept connections from outside.</source> + <translation type="unfinished">Aceptar conexiones externas.</translation> + </message> + <message> <source>Allow incomin&g connections</source> - <translation type="unfinished">Permitir conexiones entrantes</translation> + <translation type="unfinished">&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> + <translation type="unfinished">Conectarse a la red de Bitcoin a través de un proxy SOCKS5.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation type="unfinished">&Conectarse a través del proxy SOCKS5 (proxy predeterminado):</translation> </message> <message> <source>Proxy &IP:</source> - <translation type="unfinished">Dirección &IP del proxy:</translation> + <translation type="unfinished">&IP del proxy:</translation> </message> <message> <source>&Port:</source> @@ -1549,11 +1717,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation type="unfinished">Puerto del servidor proxy (ej. 9050)</translation> + <translation type="unfinished">Puerto del proxy (p. ej., 9050)</translation> </message> <message> <source>Used for reaching peers via:</source> - <translation type="unfinished">Utilizado para llegar a los compañeros a través de:</translation> + <translation type="unfinished">Usado para conectarse con pares a través de:</translation> </message> <message> <source>&Window</source> @@ -1569,35 +1737,35 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Show only a tray icon after minimizing the window.</source> - <translation type="unfinished">Minimizar la ventana a la bandeja de iconos del sistema.</translation> + <translation type="unfinished">Mostrar solo un Ãcono de bandeja después de minimizar la ventana.</translation> </message> <message> <source>&Minimize to the tray instead of the taskbar</source> - <translation type="unfinished">&Minimizar a la bandeja en vez de a la barra de tareas</translation> + <translation type="unfinished">&Minimizar a la bandeja en vez de la barra de tareas</translation> </message> <message> <source>M&inimize on close</source> - <translation type="unfinished">M&inimizar al cerrar</translation> + <translation type="unfinished">&Minimizar al cerrar</translation> </message> <message> <source>&Display</source> - <translation type="unfinished">&Interfaz</translation> + <translation type="unfinished">&Visualización</translation> </message> <message> <source>User Interface &language:</source> - <translation type="unfinished">I&dioma de la interfaz de usuario</translation> + <translation type="unfinished">&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> + <translation type="unfinished">El idioma de la interfaz de usuario puede establecerse aquÃ. Esta configuración surtirá efecto después de reiniciar %1.</translation> </message> <message> <source>&Unit to show amounts in:</source> - <translation type="unfinished">Mostrar las cantidades en la &unidad:</translation> + <translation type="unfinished">&Unidad en la que se muestran los 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> + <translation type="unfinished">Elegir la unidad de subdivisión predeterminada para mostrar en la interfaz y al enviar 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> @@ -1609,28 +1777,24 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Whether to show coin control features or not.</source> - <translation type="unfinished">Mostrar o no caracterÃsticas de control de moneda</translation> + <translation type="unfinished">Si se muestran o no las funcionalidades de control de monedas.</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> + <translation type="unfinished">Conectarse a la red de Bitcoin a través de un proxy SOCKS5 independiente para los servicios onion de Tor.</translation> </message> <message> <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> <translation type="unfinished">Usar un proxy SOCKS&5 independiente para comunicarse con pares a través de los servicios onion de Tor:</translation> </message> <message> - <source>&OK</source> - <translation type="unfinished">&Aceptar</translation> - </message> - <message> <source>&Cancel</source> <translation type="unfinished">&Cancelar</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> + <translation type="unfinished">Compilado sin compatibilidad con firma externa (requerida para la firma externa)</translation> </message> <message> <source>default</source> @@ -1643,12 +1807,12 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <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">Reinicio del cliente para activar cambios.</translation> + <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> @@ -1658,7 +1822,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">El cliente se cerrará. ¿Quieres continuar?</translation> </message> <message> <source>Configuration options</source> @@ -1668,7 +1832,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> + <translation type="unfinished">El archivo de configuración se usa para especificar opciones avanzadas del usuario, que remplazan la configuración de la GUI. Además, las opciones de la lÃnea de comandos remplazarán este archivo de configuración.</translation> </message> <message> <source>Continue</source> @@ -1680,15 +1844,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>The configuration file could not be opened.</source> - <translation type="unfinished">El archivo de configuración no se pudo abrir.</translation> + <translation type="unfinished">No se pudo abrir el archivo de configuración.</translation> </message> <message> <source>This change would require a client restart.</source> - <translation type="unfinished">Este cambio requiere reinicio por parte del cliente.</translation> + <translation type="unfinished">Estos cambios requieren reiniciar el cliente.</translation> </message> <message> <source>The supplied proxy address is invalid.</source> - <translation type="unfinished">La dirección proxy indicada es inválida.</translation> + <translation type="unfinished">La dirección del proxy proporcionada es inválida.</translation> </message> </context> <context> @@ -1702,11 +1866,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <name>OverviewPage</name> <message> <source>Form</source> - <translation type="unfinished">Desde</translation> + <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 Bitcoin después de que se haya establecido una conexión, pero este proceso aún no se ha completado.</translation> + <translation type="unfinished">La información mostrada puede estar desactualizada. La billetera 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 de observación:</translation> </message> <message> <source>Available:</source> @@ -1714,7 +1882,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current spendable balance</source> - <translation type="unfinished">Su balance actual gastable</translation> + <translation type="unfinished">Tu saldo disponible para gastar actualmente</translation> </message> <message> <source>Pending:</source> @@ -1722,15 +1890,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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">Total de transacciones que deben ser confirmadas, y que no cuentan con el balance gastable necesario</translation> + <translation type="unfinished">Total de transacciones que aún se deben confirmar y que no se contabilizan dentro del saldo disponible para gastar</translation> </message> <message> <source>Immature:</source> - <translation type="unfinished">No disponible:</translation> + <translation type="unfinished">Inmaduro:</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> + <translation type="unfinished">Saldo minado que aún no ha madurado</translation> </message> <message> <source>Balances</source> @@ -1738,15 +1906,15 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Your current total balance</source> - <translation type="unfinished">Su balance actual total</translation> + <translation type="unfinished">Tu saldo total actual</translation> </message> <message> <source>Your current balance in watch-only addresses</source> - <translation type="unfinished">Tu saldo actual en solo ver direcciones</translation> + <translation type="unfinished">Tu saldo actual en direcciones solo de observación</translation> </message> <message> <source>Spendable:</source> - <translation type="unfinished">Disponible:</translation> + <translation type="unfinished">Gastable:</translation> </message> <message> <source>Recent transactions</source> @@ -1754,22 +1922,26 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation type="unfinished">Transacciones sin confirmar a direcciones de observación</translation> + <translation type="unfinished">Transacciones sin confirmar hacia direcciones solo 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 solo de observación que aún no ha madurado</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation type="unfinished">Saldo total actual en direcciones de solo observación</translation> + <translation type="unfinished">Saldo total actual en direcciones solo de observación</translation> </message> <message> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->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->Ocultar valores.</translation> + <translation type="unfinished">Modo de privacidad activado para la pestaña de vista general. Para mostrar los valores, anula la selección de "Configuración->Ocultar valores".</translation> </message> </context> <context> <name>PSBTOperationsDialog</name> <message> <source>PSBT Operations</source> - <translation type="unfinished">Operaciones PSBT</translation> + <translation type="unfinished">Operaciones TBPF</translation> </message> <message> <source>Sign Tx</source> @@ -1805,7 +1977,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Could not sign any more inputs.</source> - <translation type="unfinished">No se pudo firmar más entradas.</translation> + <translation type="unfinished">No se pudieron firmar más entradas.</translation> </message> <message> <source>Signed %1 inputs, but more signatures are still required.</source> @@ -1829,7 +2001,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>PSBT copied to clipboard.</source> - <translation type="unfinished">PSBT copiada al portapapeles.</translation> + <translation type="unfinished">TBPF copiada al portapapeles.</translation> </message> <message> <source>Save Transaction Data</source> @@ -1842,7 +2014,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT guardada en en el disco.</translation> + <translation type="unfinished">TBPF guardada en el disco.</translation> </message> <message> <source>Sends %1 to %2</source> @@ -1850,7 +2022,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>own address</source> - <translation type="unfinished">dirección personal</translation> + <translation type="unfinished">dirección propia</translation> </message> <message> <source>Unable to calculate transaction fee or total transaction amount.</source> @@ -1862,7 +2034,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>or</source> @@ -1874,7 +2046,7 @@ El proceso de migración creará una copia de seguridad de la billetera antes de </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> + <translation type="unfinished">Falta información sobre las entradas de la transacción.</translation> </message> <message> <source>Transaction still needs signature(s).</source> @@ -1896,7 +2068,11 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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> - </context> + <message> + <source>Transaction status is unknown.</source> + <translation type="unfinished">El estado de la transacción es desconocido.</translation> + </message> +</context> <context> <name>PaymentServer</name> <message> @@ -1904,8 +2080,16 @@ El proceso de migración creará una copia de seguridad de la billetera antes de <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 el controlador "bitcoin: click-to-pay"</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> + <translation type="unfinished">"bitcoin://" no es un URI válido. Usa "bitcoin:" en su lugar.</translation> </message> <message> <source>Cannot process payment request because BIP70 is not supported. @@ -1913,11 +2097,15 @@ Due to widespread security flaws in BIP70 it's strongly recommended that any mer 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> +Si recibes este error, debes solicitar al comerciante que te 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">No se puede analizar el URI. Esto se puede deber a una dirección de Bitcoin inválida o a parámetros de URI con formato incorrecto.</translation> </message> <message> <source>Payment request file handling</source> - <translation type="unfinished">Manejo del archivo de solicitud de pago</translation> + <translation type="unfinished">Gestión del archivo de solicitud de pago</translation> </message> </context> <context> @@ -1935,12 +2123,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Antigüedad</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> </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">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>Received</source> @@ -1970,7 +2163,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>Outbound</source> <extracomment>An Outbound Connection to a Peer.</extracomment> - <translation type="unfinished">Salida</translation> + <translation type="unfinished">Saliente</translation> </message> </context> <context> @@ -1980,8 +2173,16 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">&Guardar imagen...</translation> </message> <message> + <source>&Copy Image</source> + <translation type="unfinished">&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> + <translation type="unfinished">El URI resultante es demasiado largo, asà que trata 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> @@ -2009,23 +2210,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Information</source> - <translation type="unfinished">Información</translation> + <translation type="unfinished">&Información</translation> + </message> + <message> + <source>Datadir</source> + <translation type="unfinished">Directorio de datos</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de datos, usa la opción "%1".</translation> </message> <message> <source>Blocksdir</source> - <translation type="unfinished">Bloques dir</translation> + <translation type="unfinished">Directorio de bloques</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> + <translation type="unfinished">Para especificar una ubicación no predeterminada del directorio de bloques, usa la opción "%1".</translation> </message> <message> <source>Startup time</source> - <translation type="unfinished">Hora de inicio</translation> + <translation type="unfinished">Tiempo de inicio</translation> </message> <message> <source>Network</source> @@ -2045,19 +2250,27 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Memory Pool</source> - <translation type="unfinished">Grupo de memoria</translation> + <translation type="unfinished">Pool de memoria</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation type="unfinished">Número total de transacciones</translation> </message> <message> <source>Memory usage</source> - <translation type="unfinished">Memoria utilizada</translation> + <translation type="unfinished">Uso de memoria</translation> </message> <message> <source>Wallet: </source> - <translation type="unfinished">Monedero:</translation> + <translation type="unfinished">Billetera:</translation> + </message> + <message> + <source>(none)</source> + <translation type="unfinished">(ninguna)</translation> </message> <message> <source>&Reset</source> - <translation type="unfinished">&Reestablecer</translation> + <translation type="unfinished">&Restablecer</translation> </message> <message> <source>Received</source> @@ -2065,7 +2278,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Sent</source> - <translation type="unfinished">Expedido</translation> + <translation type="unfinished">Enviado</translation> </message> <message> <source>&Peers</source> @@ -2089,13 +2302,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">Cadena de identificación de la sesión BIP324 en formato hexadecimal, si existe.</translation> + <translation type="unfinished">Cadena de identificador de la sesión BIP324 en formato hexadecimal, si existe.</translation> </message> <message> <source>Session ID</source> <translation type="unfinished">Identificador de sesión</translation> </message> <message> + <source>Version</source> + <translation type="unfinished">Versión</translation> + </message> + <message> <source>Whether we relay transactions to this peer.</source> <translation type="unfinished">Si retransmitimos las transacciones a este par.</translation> </message> @@ -2105,13 +2322,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Starting Block</source> - <translation type="unfinished">Bloque de inicio</translation> + <translation type="unfinished">Bloque inicial</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> @@ -2131,17 +2352,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Retransmisión de direcciones</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> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se procesaron (excluye las direcciones desestimadas 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> + <translation type="unfinished">El número total de direcciones recibidas desde este par que se desestimaron (no se procesaron) debido a la limitación de volumen.</translation> </message> <message> <source>Addresses Processed</source> @@ -2151,7 +2372,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <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> + <translation type="unfinished">Direcciones desestimadas por limitación de volumen</translation> </message> <message> <source>User Agent</source> @@ -2159,7 +2380,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Node window</source> - <translation type="unfinished">Ventana de nodo</translation> + <translation type="unfinished">Ventana del nodo</translation> </message> <message> <source>Current block height</source> @@ -2167,15 +2388,19 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> + <translation type="unfinished">Abrir el archivo de registro de depuración %1 en el directorio de datos actual. Esto puede tardar unos segundos para los archivos de registro grandes.</translation> </message> <message> <source>Decrease font size</source> - <translation type="unfinished">Reducir el tamaño de la fuente</translation> + <translation type="unfinished">Disminuir tamaño de fuente</translation> </message> <message> <source>Increase font size</source> - <translation type="unfinished">Aumentar el tamaño de la fuente</translation> + <translation type="unfinished">Aumentar tamaño de fuente</translation> + </message> + <message> + <source>Permissions</source> + <translation type="unfinished">Permisos</translation> </message> <message> <source>The direction and type of peer connection: %1</source> @@ -2195,13 +2420,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </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> + <translation type="unfinished">Retransmisión de bloques compactos BIP152 en 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">Tiempo de 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> @@ -2220,21 +2449,29 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Last Receive</source> - <translation type="unfinished">Ultima recepción</translation> + <translation type="unfinished">Última recepción</translation> </message> <message> <source>Ping Time</source> - <translation type="unfinished">Tiempo de Ping</translation> + <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> + <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">Desfase temporal</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Hora del último bloque</translation> </message> @@ -2248,15 +2485,15 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>&Network Traffic</source> - <translation type="unfinished">&Tráfico de Red</translation> + <translation type="unfinished">&Tráfico de red</translation> </message> <message> <source>Totals</source> - <translation type="unfinished">Total:</translation> + <translation type="unfinished">Totales</translation> </message> <message> <source>Debug log file</source> - <translation type="unfinished">Archivo de registro de depuración</translation> + <translation type="unfinished">Archivo del registro de depuración</translation> </message> <message> <source>Clear console</source> @@ -2264,11 +2501,11 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>In:</source> - <translation type="unfinished">Dentro:</translation> + <translation type="unfinished">Entrada:</translation> </message> <message> <source>Out:</source> - <translation type="unfinished">Fuera:</translation> + <translation type="unfinished">Salida:</translation> </message> <message> <source>Inbound: initiated by peer</source> @@ -2308,7 +2545,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <message> <source>v1: unencrypted, plaintext transport protocol</source> <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">v1: protocolo de transporte de texto simple sin cifrar</translation> + <translation type="unfinished">v1: protocolo de transporte de texto simple sin encriptar</translation> </message> <message> <source>v2: BIP324 encrypted transport protocol</source> @@ -2325,7 +2562,7 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>no high bandwidth relay selected</source> - <translation type="unfinished">Ninguna transmisión de banda ancha seleccionada</translation> + <translation type="unfinished">No se seleccionó la retransmisión de banda ancha</translation> </message> <message> <source>&Copy address</source> @@ -2333,21 +2570,33 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co <translation type="unfinished">&Copiar dirección</translation> </message> <message> + <source>&Disconnect</source> + <translation type="unfinished">&Desconectar</translation> + </message> + <message> <source>1 &hour</source> - <translation type="unfinished">1 hora</translation> + <translation type="unfinished">1 &hora</translation> </message> <message> <source>1 d&ay</source> <translation type="unfinished">1 &dÃa</translation> </message> <message> + <source>1 &week</source> + <translation type="unfinished">1 &semana</translation> + </message> + <message> + <source>1 &year</source> + <translation type="unfinished">1 &año</translation> + </message> + <message> <source>&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">&Copiar IP/Máscara de red</translation> </message> <message> <source>&Unban</source> - <translation type="unfinished">&Desbloquear</translation> + <translation type="unfinished">&Levantar prohibición</translation> </message> <message> <source>Network activity disabled</source> @@ -2355,13 +2604,17 @@ Si recibe este error, debe solicitar al comerciante que le proporcione un URI co </message> <message> <source>Executing command without any wallet</source> - <translation type="unfinished">Ejecutar comando sin monedero</translation> + <translation type="unfinished">Ejecutar comando sin ninguna billetera</translation> </message> <message> <source>Node window - [%1]</source> <translation type="unfinished">Ventana de nodo - [%1]</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. @@ -2370,12 +2623,13 @@ 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">Bienvenido a la consola RPC -%1. Utiliza las flechas arriba y abajo para navegar por el historial, y %2 para borrar la pantalla. + <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 un resumen de los comandos disponibles. Para más información sobre cómo usar esta consola, escribe %6. +Escribe %5 para ver los comandos disponibles. +Para obtener más información sobre cómo usar esta consola, escribe %6. -%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> +%7 ADVERTENCIA: Los estafadores suelen decirles a los usuarios que escriban comandos aquà para robarles el contenido de sus billeteras. No uses esta consola sin entender completamente las ramificaciones de un comando.%8</translation> </message> <message> <source>Executing…</source> @@ -2392,11 +2646,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Yes</source> - <translation type="unfinished">Si</translation> + <translation type="unfinished">SÃ</translation> </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>From</source> @@ -2404,11 +2658,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Ban for</source> - <translation type="unfinished">Bloqueo para</translation> + <translation type="unfinished">Prohibir por</translation> </message> <message> <source>Never</source> - <translation type="unfinished">nunca</translation> + <translation type="unfinished">Nunca</translation> </message> <message> <source>Unknown</source> @@ -2419,7 +2673,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation type="unfinished">Cantidad</translation> + <translation type="unfinished">&Importe:</translation> </message> <message> <source>&Label:</source> @@ -2427,27 +2681,27 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>&Message:</source> - <translation type="unfinished">Mensaje:</translation> + <translation type="unfinished">&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 adjunto a la solicitud de pago, que será mostrado cuando la solicitud sea abierta. Nota: Este mensaje no será enviado con el pago a través de la red Bitcoin.</translation> + <translation type="unfinished">Mensaje opcional para adjuntar a la solicitud de pago, que se mostrará cuando se abra la solicitud. Nota: Este 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">Una etiqueta opcional para asociar con la nueva dirección de recepción</translation> + <translation type="unfinished">Una 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 <b>optional</b>.</source> - <translation type="unfinished">Use este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>.</translation> + <translation type="unfinished">Usa este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>.</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> + <translation type="unfinished">Un importe opcional para solicitar. Déjalo vacÃo o ingresa cero para no solicitar un importe 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> + <translation type="unfinished">Una etiqueta opcional para asociar con la nueva dirección de recepción (puedes usarla 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> @@ -2455,23 +2709,23 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>&Create new receiving address</source> - <translation type="unfinished">&Crear una nueva dirección de recepción</translation> + <translation type="unfinished">&Crear 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> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Clear</source> - <translation type="unfinished">Limpiar</translation> + <translation type="unfinished">Borrar</translation> </message> <message> <source>Requested payments history</source> - <translation type="unfinished">Historial de pagos solicitado</translation> + <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">Muestra la petición seleccionada (También doble clic)</translation> + <translation type="unfinished">Mostrar la solicitud seleccionada (equivale a hacer doble clic en una entrada)</translation> </message> <message> <source>Show</source> @@ -2479,7 +2733,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Remove the selected entries from the list</source> - <translation type="unfinished">Borrar de la lista las direcciónes actualmente seleccionadas</translation> + <translation type="unfinished">Eliminar las entradas seleccionadas de la lista</translation> </message> <message> <source>Remove</source> @@ -2527,7 +2781,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Could not generate new %1 address</source> - <translation type="unfinished">No se ha podido generar una nueva dirección %1</translation> + <translation type="unfinished">No se pudo generar nueva dirección %1</translation> </message> </context> <context> @@ -2537,20 +2791,32 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Solicitar pago a...</translation> </message> <message> + <source>Address:</source> + <translation type="unfinished">Dirección:</translation> + </message> + <message> <source>Amount:</source> - <translation type="unfinished">CuantÃa:</translation> + <translation type="unfinished">Importe:</translation> + </message> + <message> + <source>Label:</source> + <translation type="unfinished">Etiqueta:</translation> </message> <message> <source>Message:</source> <translation type="unfinished">Mensaje:</translation> </message> <message> + <source>Wallet:</source> + <translation type="unfinished">Billetera:</translation> + </message> + <message> <source>Copy &URI</source> <translation type="unfinished">Copiar &URI</translation> </message> <message> <source>Copy &Address</source> - <translation type="unfinished">Copiar &Dirección</translation> + <translation type="unfinished">Copiar &dirección</translation> </message> <message> <source>&Verify</source> @@ -2558,13 +2824,21 @@ 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, por ejemplo, en la pantalla de una billetera de hardware</translation> + <translation type="unfinished">Verificar esta dirección, por ejemplo, en la pantalla de una billetera de hardware.</translation> </message> <message> <source>&Save Image…</source> <translation type="unfinished">&Guardar imagen...</translation> </message> - </context> + <message> + <source>Payment information</source> + <translation type="unfinished">Información del pago</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation type="unfinished">Solicitar pago a %1</translation> + </message> +</context> <context> <name>RecentRequestsTableModel</name> <message> @@ -2576,6 +2850,10 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià <translation type="unfinished">Etiqueta</translation> </message> <message> + <source>Message</source> + <translation type="unfinished">Mensaje</translation> + </message> + <message> <source>(no label)</source> <translation type="unfinished">(sin etiqueta)</translation> </message> @@ -2585,7 +2863,7 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>(no amount requested)</source> - <translation type="unfinished">(sin importe solicitado)</translation> + <translation type="unfinished">(no se solicitó un importe)</translation> </message> <message> <source>Requested</source> @@ -2600,15 +2878,15 @@ 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">Funciones de control de monedas</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished">Seleccionado automaticamente</translation> + <translation type="unfinished">seleccionado automáticamente</translation> </message> <message> <source>Insufficient funds!</source> - <translation type="unfinished">Fondos insuficientes!</translation> + <translation type="unfinished">Fondos insuficientes</translation> </message> <message> <source>Quantity:</source> @@ -2616,15 +2894,15 @@ 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> - <translation type="unfinished">Tasa:</translation> + <translation type="unfinished">Comisión:</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Después de tasas:</translation> + <translation type="unfinished">Después de la comisión:</translation> </message> <message> <source>Change:</source> @@ -2632,11 +2910,11 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </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> + <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 propia</translation> + <translation type="unfinished">Dirección de cambio personalizada</translation> </message> <message> <source>Transaction Fee:</source> @@ -2644,11 +2922,19 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </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> + <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> - <translation type="unfinished">Advertencia: En este momento no se puede estimar la cuota.</translation> + <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> @@ -2660,15 +2946,15 @@ Escribe %5 para ver un resumen de los comandos disponibles. Para más informacià </message> <message> <source>Send to multiple recipients at once</source> - <translation type="unfinished">Enviar a múltiples destinatarios de una vez</translation> + <translation type="unfinished">Enviar a múltiples destinatarios a la vez</translation> </message> <message> <source>Add &Recipient</source> - <translation type="unfinished">Añadir &destinatario</translation> + <translation type="unfinished">Agregar &destinatario</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation type="unfinished">Limpiar todos los campos del formulario</translation> + <translation type="unfinished">Borrar todos los campos del formulario.</translation> </message> <message> <source>Inputs…</source> @@ -2696,19 +2982,27 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">Una comisión demasiado pequeña puede resultar en una transacción que nunca será confirmada (leer herramientas de información).</translation> + <translation type="unfinished">Si la comisión es demasiado baja, es posible que la transacción nunca se confirme (leer la información en pantalla).</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 "Remplazar 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> + <translation type="unfinished">Con la función "Remplazar 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 &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>Balance:</source> @@ -2728,7 +3022,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar cantidad</translation> + <translation type="unfinished">Copiar importe</translation> </message> <message> <source>Copy fee</source> @@ -2736,7 +3030,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar después de la tarifa</translation> + <translation type="unfinished">Copiar después de la comisión</translation> </message> <message> <source>Copy bytes</source> @@ -2747,22 +3041,34 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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">Firmar en el dispositivo</translation> </message> <message> <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Conecta tu monedero externo primero.</translation> + <translation type="unfinished">Conecta primero tu billetera de hardware.</translation> </message> <message> <source>Set external signer script path in Options -> Wallet</source> <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Configura una ruta externa al script en Opciones -> Monedero</translation> + <translation type="unfinished">Establecer la ruta al script del firmante externo en "Opciones -> Billetera"</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation type="unfinished">&Crear 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> + <translation type="unfinished">Crea una transacción de Bitcoin parcialmente firmada (TBPF) para usarla, por ejemplo, con una billetera %1 sin conexión o una billetera de hardware compatible con TBPF.</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation type="unfinished">%1 a '%2'</translation> </message> <message> <source>%1 to %2</source> @@ -2774,17 +3080,17 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Sign failed</source> - <translation type="unfinished">La firma falló</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <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">Dispositivo externo de firma no encontrado</translation> + <translation type="unfinished">Error de firmante externo</translation> </message> <message> <source>Save Transaction Data</source> @@ -2798,7 +3104,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">TBPF guardado </translation> + <translation type="unfinished">TBPF guardada</translation> </message> <message> <source>External balance:</source> @@ -2810,11 +3116,16 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Puedes aumentar la comisión después (indica "Remplazar 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 (TBPF) que puedes guardar o copiar y, luego, firmar; por ejemplo, una billetera %1 fuera de lÃnea o una billetera de hardware compatible con TBPF.</translation> </message> <message> <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 desde monedero '%2'</translation> + <translation type="unfinished">%1 desde billetera "%2"</translation> </message> <message> <source>Do you want to create this transaction?</source> @@ -2824,12 +3135,12 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">Revisa la transacción. Puedes crear y enviar esta transacción de Bitcoin parcialmente firmada (TBPF), 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 TBPF.</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, revisa tu transacción</translation> + <translation type="unfinished">Revisa la transacción.</translation> </message> <message> <source>Transaction fee</source> @@ -2837,25 +3148,29 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">No indica remplazar-por-comisión, BIP-125.</translation> + <translation type="unfinished">No indica "Remplazar por comisión", BIP-125.</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Cantidad total</translation> + <translation type="unfinished">Importe total</translation> </message> <message> <source>Unsigned Transaction</source> <comment>PSBT copied</comment> <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> - <translation type="unfinished">Transacción no asignada</translation> + <translation type="unfinished">Transacción sin firmar</translation> </message> <message> <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">Se copió la PSBT al portapapeles. También puedes guardarla.</translation> + <translation type="unfinished">Se copió la TBPF al portapapeles. También puedes guardarla.</translation> </message> <message> <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT guardada en el disco</translation> + <translation type="unfinished">TBPF guardada en el disco</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> @@ -2867,7 +3182,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">La cantidad por pagar tiene que ser mayor que 0.</translation> + <translation type="unfinished">El importe por pagar tiene que ser mayor que 0.</translation> </message> <message> <source>The amount exceeds your balance.</source> @@ -2875,38 +3190,42 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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 tasa de envÃo de %1</translation> + <translation type="unfinished">El total sobrepasa el saldo cuando se incluye la comisión de transacción de %1.</translation> </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> <translation type="unfinished">Se encontró una dirección duplicada: las direcciones solo se deben usar 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 absurda-mente alta.</translation> + <translation type="unfinished">Una comisión mayor que %1 se considera absurdamente alta.</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Estimado para comenzar confirmación dentro de %n bloque.</numerusform> - <numerusform>Estimado para comenzar confirmación dentro de %n bloques.</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> <source>Warning: Invalid Bitcoin address</source> - <translation type="unfinished">Alerta: Dirección de Bitcoin inválida</translation> + <translation type="unfinished">Advertencia: Dirección de Bitcoin inválida</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation type="unfinished">Peligro: Dirección de cambio desconocida</translation> + <translation type="unfinished">Advertencia: Dirección de cambio desconocida</translation> </message> <message> <source>Confirm custom change address</source> - <translation type="unfinished">Confirmar dirección de cambio personalizada</translation> + <translation type="unfinished">Confirmar la 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> + <translation type="unfinished">La dirección que seleccionaste para el cambio no es parte de esta billetera. Una parte o la totalidad de los fondos en la billetera se enviará a esta dirección. ¿Seguro deseas continuar?</translation> </message> <message> <source>(no label)</source> @@ -2917,11 +3236,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation type="unfinished">Ca&ntidad:</translation> + <translation type="unfinished">&Importe:</translation> </message> <message> <source>Pay &To:</source> - <translation type="unfinished">&Pagar a:</translation> + <translation type="unfinished">Pagar &a:</translation> </message> <message> <source>&Label:</source> @@ -2929,25 +3248,33 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Choose previously used address</source> - <translation type="unfinished">Escoger dirección previamente usada</translation> + <translation type="unfinished">Seleccionar dirección usada anteriormente</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> + <translation type="unfinished">La dirección de 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> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> <message> <source>Remove this entry</source> - <translation type="unfinished">Eliminar esta transacción</translation> + <translation type="unfinished">Eliminar 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 importe que se envÃa. El destinatario recibirá menos bitcoins que los que ingreses en el campo del importe. Si se seleccionan varios destinatarios, la comisión se dividirá por igual.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation type="unfinished">&Restar la comisión del importe</translation> + </message> + <message> <source>Use available balance</source> <translation type="unfinished">Usar el saldo disponible</translation> </message> @@ -2957,11 +3284,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Ingresar una etiqueta para esta dirección a fin de agregarla 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á enviado a través de la red de Bitcoin.</translation> + <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> @@ -2979,7 +3306,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Firmas - Firmar / verificar un mensaje</translation> + <translation type="unfinished">Firmas: firmar o verificar un mensaje</translation> </message> <message> <source>&Sign Message</source> @@ -2987,23 +3314,23 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <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">La dirección Bitcoin con la que se firmó el mensaje</translation> + <translation type="unfinished">La dirección de Bitcoin con la que se firmará el mensaje</translation> </message> <message> <source>Choose previously used address</source> - <translation type="unfinished">Escoger dirección previamente usada</translation> + <translation type="unfinished">Seleccionar dirección usada anteriormente</translation> </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">Pegar dirección desde portapapeles</translation> + <translation type="unfinished">Pegar dirección desde el portapapeles</translation> </message> <message> <source>Enter the message you want to sign here</source> - <translation type="unfinished">Introduzca el mensaje que desea firmar aquÃ</translation> + <translation type="unfinished">Ingresar aquà el mensaje que deseas firmar</translation> </message> <message> <source>Signature</source> @@ -3015,7 +3342,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Firmar el mensaje para demostrar que se posee esta dirección Bitcoin</translation> + <translation type="unfinished">Firmar el mensaje para demostrar que esta dirección de Bitcoin te pertenece</translation> </message> <message> <source>Sign &Message</source> @@ -3023,19 +3350,23 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Reset all sign message fields</source> - <translation type="unfinished">Limpiar todos los campos de la firma de mensaje</translation> + <translation type="unfinished">Restablecer todos los campos de firma de mensaje</translation> </message> <message> <source>Clear &All</source> - <translation type="unfinished">Limpiar &todo</translation> + <translation type="unfinished">Borrar &todo</translation> </message> <message> <source>&Verify Message</source> <translation type="unfinished">&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">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> + <translation type="unfinished">La dirección de Bitcoin con la que se firmó el mensaje</translation> </message> <message> <source>The signed message to verify</source> @@ -3043,11 +3374,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>The signature given when the message was signed</source> - <translation type="unfinished">La firma proporcionada cuando el mensaje fue firmado</translation> + <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">Verificar el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation> + <translation type="unfinished">Verifica el mensaje para asegurarte de que se firmó con la dirección de Bitcoin especificada.</translation> </message> <message> <source>Verify &Message</source> @@ -3055,31 +3386,39 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Reset all verify message fields</source> - <translation type="unfinished">Limpiar todos los campos de la verificación de mensaje</translation> + <translation type="unfinished">Restablecer todos los campos de 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> + <translation type="unfinished">Hacer clic en "Firmar mensaje" para generar una firma</translation> </message> <message> <source>The entered address is invalid.</source> - <translation type="unfinished">La dirección introducida es inválida</translation> + <translation type="unfinished">La dirección ingresada 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> + <translation type="unfinished">Revisa la dirección e intenta de nuevo.</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> + <translation type="unfinished">La dirección ingresada no corresponde a una clave.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation type="unfinished">Se canceló el desbloqueo de la billetera.</translation> </message> <message> <source>No error</source> - <translation type="unfinished">No hay error</translation> + <translation type="unfinished">Sin error </translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation type="unfinished">La clave privada para la dirección ingresada no está disponible.</translation> </message> <message> <source>Message signing failed.</source> - <translation type="unfinished">Ha fallado la firma del mensaje.</translation> + <translation type="unfinished">Error al firmar el mensaje.</translation> </message> <message> <source>Message signed.</source> @@ -3091,27 +3430,40 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Please check the signature and try again.</source> - <translation type="unfinished">Compruebe la firma e inténtelo de nuevo.</translation> + <translation type="unfinished">Comprueba la firma e intenta 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> + <translation type="unfinished">La firma no coincide con la sÃntesis del mensaje.</translation> </message> - </context> + <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> <source>(press q to shutdown and continue later)</source> - <translation type="unfinished">(presiona q para apagar y seguir luego)</translation> + <translation type="unfinished">(Presionar q para apagar y seguir luego)</translation> </message> <message> <source>press q to shutdown</source> - <translation type="unfinished">presiona q para apagar </translation> + <translation type="unfinished">Presionar 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 una transacción con %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 el pool de memoria</translation> @@ -3134,7 +3486,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">%1 confirmaciones</translation> </message> <message> <source>Status</source> @@ -3149,6 +3501,10 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <translation type="unfinished">Fuente</translation> </message> <message> + <source>Generated</source> + <translation type="unfinished">Generado</translation> + </message> + <message> <source>From</source> <translation type="unfinished">De</translation> </message> @@ -3158,11 +3514,23 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>To</source> - <translation type="unfinished">Para</translation> + <translation type="unfinished">A</translation> </message> <message> <source>own address</source> - <translation type="unfinished">dirección personal</translation> + <translation type="unfinished">dirección propia</translation> + </message> + <message> + <source>watch-only</source> + <translation type="unfinished">Solo de 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> @@ -3176,8 +3544,16 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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 enviado</translation> + <translation type="unfinished">Débito total</translation> + </message> + <message> + <source>Total credit</source> + <translation type="unfinished">Crédito total</translation> </message> <message> <source>Transaction fee</source> @@ -3185,7 +3561,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Net amount</source> - <translation type="unfinished">Cantidad total</translation> + <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> @@ -3193,7 +3577,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Transaction total size</source> - <translation type="unfinished">Tamaño total transacción</translation> + <translation type="unfinished">Tamaño total de transacción</translation> </message> <message> <source>Transaction virtual size</source> @@ -3201,7 +3585,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Output index</source> - <translation type="unfinished">Indice de salida</translation> + <translation type="unfinished">Ãndice de salida</translation> </message> <message> <source>%1 (Certificate was not verified)</source> @@ -3209,13 +3593,17 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Merchant</source> - <translation type="unfinished">Vendedor</translation> + <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 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> + <message> <source>Transaction</source> <translation type="unfinished">Transacción</translation> </message> @@ -3225,20 +3613,28 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Amount</source> - <translation type="unfinished">Cantidad</translation> + <translation type="unfinished">Importe</translation> </message> <message> <source>true</source> <translation type="unfinished">verdadero</translation> </message> - </context> + <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> + <translation type="unfinished">En este panel se muestra una descripción detallada de la transacción</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation type="unfinished">Detalles para %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> @@ -3254,16 +3650,28 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> + <translation type="unfinished">Inmadura (%1 confirmaciones; estará disponibles después de %2)</translation> </message> <message> <source>Generated but not accepted</source> @@ -3271,11 +3679,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Received with</source> - <translation type="unfinished">Recibido con</translation> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Received from</source> - <translation type="unfinished">Recibido de</translation> + <translation type="unfinished">Recibida de</translation> </message> <message> <source>Sent to</source> @@ -3283,19 +3691,35 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> + </message> + <message> + <source>watch-only</source> + <translation type="unfinished">Solo de observación</translation> + </message> + <message> + <source>(n/a)</source> + <translation type="unfinished">(n/d)</translation> </message> <message> <source>(no label)</source> <translation type="unfinished">(sin etiqueta)</translation> </message> <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation type="unfinished">Estado de la transacción. Pasa el mouse 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 en las que 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> + <translation type="unfinished">Si una dirección solo de observación está involucrada en esta transacción o no.</translation> </message> <message> <source>User-defined intent/purpose of the transaction.</source> @@ -3309,6 +3733,14 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <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> @@ -3318,11 +3750,15 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Last month</source> - <translation type="unfinished">El mes pasado </translation> + <translation type="unfinished">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> + <translation type="unfinished">Recibida con</translation> </message> <message> <source>Sent to</source> @@ -3330,7 +3766,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Mined</source> - <translation type="unfinished">Minado</translation> + <translation type="unfinished">Minada</translation> </message> <message> <source>Other</source> @@ -3338,7 +3774,7 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </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> + <translation type="unfinished">Ingresar la dirección, el identificador de transacción o la etiqueta para buscar</translation> </message> <message> <source>Min amount</source> @@ -3362,11 +3798,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Copy transaction &ID</source> - <translation type="unfinished">Copiar &ID de transacción</translation> + <translation type="unfinished">Copiar &identificador de transacción</translation> </message> <message> <source>Copy &raw transaction</source> - <translation type="unfinished">Copiar transacción &raw</translation> + <translation type="unfinished">Copiar transacción &sin procesar</translation> </message> <message> <source>Copy full transaction &details</source> @@ -3404,7 +3840,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmado</translation> + <translation type="unfinished">Confirmada</translation> + </message> + <message> + <source>Watch-only</source> + <translation type="unfinished">Solo de observación</translation> </message> <message> <source>Date</source> @@ -3423,8 +3863,12 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k <translation type="unfinished">Dirección</translation> </message> <message> + <source>ID</source> + <translation type="unfinished">Identificador</translation> + </message> + <message> <source>Exporting Failed</source> - <translation type="unfinished">La exportación falló</translation> + <translation type="unfinished">Error al exportar</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> @@ -3432,11 +3876,11 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k </message> <message> <source>Exporting Successful</source> - <translation type="unfinished">Exportación satisfactoria</translation> + <translation type="unfinished">Exportación correcta</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> + <translation type="unfinished">El historial de transacciones se guardó correctamente en %1.</translation> </message> <message> <source>Range:</source> @@ -3454,8 +3898,8 @@ Nota: Dado que la comisión se calcula por byte, una tasa de "100 satoshis por k Go to File > Open Wallet to load a wallet. - OR -</source> <translation type="unfinished">No se cargó ninguna billetera. -Ir a Archivo > Abrir billetera para cargar una. -- OR -</translation> +Ir a "Archivo > Abrir billetera" para cargar una. +- O -</translation> </message> <message> <source>Create a new wallet</source> @@ -3463,19 +3907,23 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">No se puede decodificar la TBPF desde el portapapeles (Base64 inválida)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation type="unfinished">Cargar datos de la transacción</translation> </message> <message> <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished">Transacción firmada parcialmente (*.psbt)</translation> + <translation type="unfinished">Transacción parcialmente firmada (*.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> + <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">No se puede decodificar PSBT</translation> + <translation type="unfinished">No se puede decodificar TBPF</translation> </message> </context> <context> @@ -3486,18 +3934,30 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Fee bump error</source> - <translation type="unfinished">Error de incremento de cuota</translation> + <translation type="unfinished">Error de incremento de comisión</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation type="unfinished">Fallo al incrementar 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 cuota?</translation> + <translation type="unfinished">¿Deseas 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: 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> @@ -3511,7 +3971,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>PSBT copied</source> - <translation type="unfinished">PSBT copiada</translation> + <translation type="unfinished">TBPF copiada</translation> </message> <message> <source>Copied to clipboard</source> @@ -3520,7 +3980,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Can't sign transaction.</source> - <translation type="unfinished">No se ha podido firmar la transacción.</translation> + <translation type="unfinished">No se puede firmar la transacción.</translation> </message> <message> <source>Could not commit transaction</source> @@ -3532,7 +3992,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>default wallet</source> - <translation type="unfinished">billetera por defecto</translation> + <translation type="unfinished">billetera predeterminada</translation> </message> </context> <context> @@ -3543,11 +4003,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar a un archivo los datos de esta pestaña</translation> + <translation type="unfinished">Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> <source>Backup Wallet</source> - <translation type="unfinished">Billetera de Respaldo</translation> + <translation type="unfinished">Realizar copia de seguridad de la billetera</translation> </message> <message> <source>Wallet Data</source> @@ -3560,15 +4020,15 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>There was an error trying to save the wallet data to %1.</source> - <translation type="unfinished">Hubo un error intentando guardar los datos de la billetera al %1</translation> + <translation type="unfinished">Ocurrió un error al intentar guardar los datos de la billetera en %1.</translation> </message> <message> <source>Backup Successful</source> - <translation type="unfinished">Copia de seguridad completada</translation> + <translation type="unfinished">Copia de seguridad correcta</translation> </message> <message> <source>The wallet data was successfully saved to %1.</source> - <translation type="unfinished">Los datos de la billetera fueron guardados exitosamente al %1</translation> + <translation type="unfinished">Los datos de la billetera se guardaron correctamente en %1.</translation> </message> <message> <source>Cancel</source> @@ -3583,11 +4043,11 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">%s dañado. Trata de usar la herramienta de la billetera de Bitcoin para rescatar o restaurar una copia de seguridad.</translation> </message> <message> <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> - <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea no válida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Comunique este incidente a %s, indicando cómo obtuvo la instantánea. Se dejó el estado de encadenamiento de la instantánea no válida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> + <translation type="unfinished">%s no pudo validar el estado de la instantánea -assumeutxo. Esto indica un problema de hardware, un error en el software o una modificación incorrecta del software que permitió que se cargara una instantánea inválida. Por consiguiente, el nodo se apagará y dejará de utilizar cualquier estado basado en la instantánea, restableciendo la altura de la cadena de %d a %d. En el siguiente reinicio, el nodo reanudará la sincronización desde %d sin usar datos de instantánea. Reporta este incidente a %s, indicando cómo obtuviste la instantánea. Se dejó el estado de cadena de la instantánea inválida en el disco por si resulta útil para diagnosticar el problema que causó este error.</translation> </message> <message> <source>%s request to listen on port %u. This port is considered "bad" 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> @@ -3610,28 +4070,32 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Es posible que el espacio en disco %s no tenga capacidad para los archivos de bloque. Aproximadamente %u GB de datos se almacenarán en este directorio.</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; ver el archivo adjunto %s o %s.</translation> + </message> + <message> <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">Error al cargar la billetera. Esta requiere que se descarguen bloques, y el software actualmente no admite la carga de billeteras mientras los bloques se descargan fuera de orden, cuando se usan instantáneas de assumeutxo. La billetera deberÃa poder cargarse correctamente después de que la sincronización del nodo alcance la altura %s.</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> + <translation type="unfinished">¡Error al leer %s! Es probable que falten los datos de la transacción o que sean incorrectos. Rescaneando 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> + <translation type="unfinished">Error: El registro del formato del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: El registro del identificador del archivo de volcado es incorrecto. Se obtuvo "%s", mientras que 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> + <translation type="unfinished">Error: La versión del archivo de 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> + <translation type="unfinished">Error: Las billeteras "legacy" solo admiten los tipos de dirección "legacy", "p2sh-segwit" y "bech32".</translation> </message> <message> <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> @@ -3643,7 +4107,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El archivo peers.dat (%s) es inválido o está dañado. 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>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> @@ -3670,8 +4134,12 @@ Ir a Archivo > Abrir billetera para cargar una. <translation type="unfinished">Contribuye si te parece que %s es útil. Visita %s para obtener más información sobre el software.</translation> </message> <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation type="unfinished">La poda se configuró por debajo del mÃnimo de %d MiB. Usa un valor más alto.</translation> + </message> + <message> <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> - <translation type="unfinished">El modo de poda no es compatible con -reindex-chainstate. Usa en su lugar un -reindex completo.</translation> + <translation type="unfinished">El modo de poda es incompatible con -reindex-chainstate. Usa en su lugar un -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> @@ -3679,7 +4147,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>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.</source> - <translation type="unfinished">Error de renombrado de «%s» → «%s». DeberÃa resolver esto manualmente moviendo o borrando el directorio %s de la instantánea no válida, en otro caso encontrará el mismo error de nuevo en el arranque siguiente.</translation> + <translation type="unfinished">Error al cambiar el nombre de "%s" a "%s". Para resolverlo, mueve o elimina manualmente el directorio %s de la instantánea no válida. De lo contrario, encontrarás el mismo error de nuevo en el siguiente inicio.</translation> </message> <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> @@ -3691,7 +4159,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">El importe de la transacción es demasiado pequeño para enviarlo después de deducir 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> @@ -3699,7 +4167,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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 compilación de prueba pre-lanzamiento - use bajo su propio riesgo - no utilizar para aplicaciones de minerÃa o mercantes</translation> + <translation type="unfinished">Esta es una compilación preliminar de prueba. Úsala bajo tu propia responsabilidad. No la uses para aplicaciones 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> @@ -3707,15 +4175,15 @@ Ir a Archivo > Abrir billetera para cargar una. </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> + <translation type="unfinished">Esta es la comisión de transacción que puedes descartar si el cambio es más pequeño que el remanente en este nivel.</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation type="unfinished">Impuesto por transacción que pagarás cuando la estimación de impuesto no esté disponible.</translation> + <translation type="unfinished">Esta es la comisión de transacción que puedes pagar cuando los cálculos de comisiones no estén disponibles.</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> + <translation type="unfinished">La longitud total de la cadena de versión de red ( %i) supera la longitud máxima (%i). Reduce 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> @@ -3727,7 +4195,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <translation type="unfinished">Nivel de boletÃn del acceso especificado en categorÃa no mantenida en %1$s=%2$s. Se esperaba %1$s=<category>:<loglevel>. CategorÃas válidas: %3$s. Niveles de boletÃn válidos: %4 $s.</translation> + <translation type="unfinished">El nivel de registro de la categorÃa especÃfica no es compatible: %1$s=%2$s. Se esperaba %1$s=<category>:<loglevel>. CategorÃas válidas: %3$s. Niveles de registro válidos: %4 $s.</translation> </message> <message> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> @@ -3739,11 +4207,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> - <translation type="unfinished">Monedero correctamente cargado. El tipo de billetero heredado está siendo obsoleto y mantenimiento para creación de monederos heredados serán eliminados en el futuro. Los monederos heredados pueden ser migrados a un descriptor de monedero con migratewallet.</translation> + <translation type="unfinished">La billetera se creó correctamente. El tipo de billetera "legacy" se está descontinuando, por lo que la asistencia para crear y abrir estas billeteras se eliminará en el futuro. Las billeteras "legacy" se pueden migrar a una billetera basada en descriptores con "migratewallet".</translation> </message> <message> <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <translation type="unfinished">Advertencia: el formato de la billetera del archivo de volcado "%s" no coincide con el formato especificado en la lÃnea de comandos "%s".</translation> + <translation type="unfinished">Advertencia: El formato de la billetera 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> @@ -3751,7 +4219,7 @@ Ir a Archivo > Abrir billetera para cargar una. </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">Aviso: ¡No parecen estar totalmente de acuerdo con nuestros compañeros! Puede que tengas que actualizar, u otros nodos tengan que actualizarce.</translation> + <translation type="unfinished">Advertencia: Al parecer no estamos completamente de acuerdo con nuestros pares. Es posible que tengas que realizar una actualización, o que los demás nodos tengan que hacerlo.</translation> </message> <message> <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> @@ -3763,7 +4231,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>%s is set very high!</source> - <translation type="unfinished">¡%s esta configurado muy alto!</translation> + <translation type="unfinished">¡El valor de %s es muy alto!</translation> </message> <message> <source>-maxmempool must be at least %d MB</source> @@ -3775,7 +4243,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">No se puede resolver -%s direccion: '%s'</translation> + <translation type="unfinished">No se puede resolver la dirección de -%s: "%s"</translation> </message> <message> <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> @@ -3791,7 +4259,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> - <translation type="unfinished">La configuración de %s es demasiado alta. Las comisiones tan grandes se podrÃan pagar en una sola transacción.</translation> + <translation type="unfinished">El valor establecido para %s es demasiado alto. Las comisiones tan grandes se podrÃan pagar en una sola transacción.</translation> </message> <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> @@ -3803,7 +4271,7 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> - <translation type="unfinished">Error leyendo %s. Todas las teclas leÃdas correctamente, pero los datos de transacción o metadatos de dirección puedan ser ausentes o incorrectos.</translation> + <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 metadatos de direcciones, o bien que sean incorrectos.</translation> </message> <message> <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> @@ -3855,11 +4323,11 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> - <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar una cantidad menor o consolidar manualmente las UTXO de la billetera.</translation> + <translation type="unfinished">El tamaño de las entradas supera el peso máximo. Intenta enviar un importe menor o consolidar manualmente las UTXO de la billetera.</translation> </message> <message> <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">La cantidad total de monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> + <translation type="unfinished">El monto total de las monedas preseleccionadas no cubre la meta de la transacción. Permite que se seleccionen automáticamente otras entradas o incluye más monedas manualmente.</translation> </message> <message> <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> @@ -3867,18 +4335,18 @@ Ir a Archivo > Abrir billetera para cargar una. </message> <message> <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> - <translation type="unfinished">No se validó la instantánea de la UTXO. Reinicia para reanudar la descarga normal del bloque inicial o intenta cargar una instantánea diferente.</translation> + <translation type="unfinished">No se validó la instantánea de UTXO. Reinicia para reanudar la descarga de bloques inicial normal o intenta cargar una instantánea diferente.</translation> </message> <message> <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> - <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará el pool de memoria.</translation> + <translation type="unfinished">Las UTXO sin confirmar están disponibles, pero si se gastan, se crea una cadena de transacciones que rechazará la mempool.</translation> </message> <message> <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">Se encontró una entrada heredada inesperada en la billetera del descriptor. Cargando billetera%s + <translation type="unfinished">Se encontró una entrada inesperada tipo "legacy" en la billetera basada en descriptores. Cargando billetera%s Es posible que la billetera haya sido manipulada o creada con malas intenciones. </translation> @@ -3912,8 +4380,16 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Se interrumpió la verificación de bloques</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation type="unfinished">La configuración para %s solo se aplica en la red %s cuando se encuentra en la sección [%s].</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation type="unfinished">Derechos de autor (C) %i-%i</translation> + </message> + <message> <source>Corrupted block database detected</source> - <translation type="unfinished">Corrupción de base de datos de bloques detectada.</translation> + <translation type="unfinished">Se detectó que la base de datos de bloques está dañada.</translation> </message> <message> <source>Could not find asmap file %s</source> @@ -3933,7 +4409,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Done loading</source> - <translation type="unfinished">Generado pero no aceptado</translation> + <translation type="unfinished">Carga completa</translation> </message> <message> <source>Dump file %s does not exist.</source> @@ -3953,7 +4429,11 @@ No se puede restaurar la copia de seguridad de la billetera.</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> + <translation type="unfinished">Error al inicializar el entorno de la base de datos de la billetera %s.</translation> + </message> + <message> + <source>Error loading %s</source> + <translation type="unfinished">Error al cargar %s</translation> </message> <message> <source>Error loading %s: Private keys can only be disabled during creation</source> @@ -3961,19 +4441,19 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error loading %s: Wallet corrupted</source> - <translation type="unfinished">Error cargando %s: Monedero corrupto</translation> + <translation type="unfinished">Error al cargar %s: billetera dañada</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> + <translation type="unfinished">Error al cargar %s: la billetera requiere una versión más reciente de %s</translation> </message> <message> <source>Error loading block database</source> - <translation type="unfinished">Error cargando base de datos de bloques</translation> + <translation type="unfinished">Error al cargar la 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> + <translation type="unfinished">Error al abrir la base de datos de bloques</translation> </message> <message> <source>Error reading configuration file: %s</source> @@ -3993,7 +4473,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">Error: no se puede extraer el destino del scriptpubkey generado</translation> + <translation type="unfinished">Error: No se puede extraer el destino del scriptpubkey generado</translation> </message> <message> <source>Error: Couldn't create cursor into database</source> @@ -4013,11 +4493,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió una clave que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió una clave que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">Error: Se recibió un valor que no es hex: %s</translation> + <translation type="unfinished">Error: Se recibió un valor que no es hexadecimal (%s)</translation> </message> <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> @@ -4037,15 +4517,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: This wallet is already a descriptor wallet</source> - <translation type="unfinished">Error: Esta billetera ya es de descriptores</translation> + <translation type="unfinished">Error: Esta billetera ya está basada en descriptores</translation> </message> <message> <source>Error: Unable to begin reading all records in the database</source> - <translation type="unfinished">Error: No se puede comenzar a leer todos los registros en la base de datos</translation> + <translation type="unfinished">Error: No se pueden 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 se puede realizar una copia de seguridad de tu billetera</translation> + <translation type="unfinished">Error: No se puede realizar una copia de seguridad de la billetera</translation> </message> <message> <source>Error: Unable to parse version %u as a uint32_t</source> @@ -4057,7 +4537,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Error: no es capaz de leer el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo leer el registro del mejor localizador de bloques de la billetera.</translation> </message> <message> <source>Error: Unable to remove watchonly address book data</source> @@ -4069,16 +4549,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor registro del localizador del bloque del monedero</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solucionable.</translation> </message> <message> <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Error: no es capaz de escribir el mejor monedero vigilado del bloque del registro localizador</translation> + <translation type="unfinished">Error: No se pudo escribir el registro del mejor localizador de bloques de la billetera solo de observación.</translation> </message> <message> <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera 1%s - </translation> + <translation type="unfinished">Error: falló copia de la libreta de direcciones para la billetera %s</translation> </message> <message> <source>Error: database transaction cannot be executed for wallet %s</source> @@ -4086,7 +4565,7 @@ No se puede restaurar la copia de seguridad de la billetera.</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. Use -listen=0 si desea esto.</translation> + <translation type="unfinished">Fallo al escuchar en todos los puertos. Usa -listen=0 si quieres hacerlo.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> @@ -4094,7 +4573,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Es erróneo al iniciar indizados, se apaga...</translation> + <translation type="unfinished">Error al iniciar Ãndices, cerrando...</translation> </message> <message> <source>Failed to verify database</source> @@ -4102,7 +4581,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Failure removing transaction: %s</source> - <translation type="unfinished">Error al eliminar la transacción: 1%s</translation> + <translation type="unfinished">Error al eliminar la transacción: %s</translation> </message> <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> @@ -4118,15 +4597,19 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation type="unfinished">Incorrecto o bloque de génesis no encontrado. Datadir equivocada para la red?</translation> + <translation type="unfinished">El bloque génesis es incorrecto o no se encontró. ¿El directorio de datos es equivocado para la red?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation type="unfinished">Fallo al inicializar la comprobación de estado. %s se cerrará.</translation> </message> <message> <source>Input not found or already spent</source> - <translation type="unfinished">No se encontró o ya se gastó la entrada</translation> + <translation type="unfinished">La entrada no se encontró o ya se gastó</translation> </message> <message> <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">dbcache insuficiente para la verificación de bloques</translation> + <translation type="unfinished">Dbcache insuficiente para la verificación de bloques</translation> </message> <message> <source>Insufficient funds</source> @@ -4134,15 +4617,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">La dirección -i2psam o el nombre de host no es válido: "%s" </translation> + <translation type="unfinished">Dirección o nombre de host de -i2psam inválido: "%s" </translation> </message> <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -onion o dominio '%s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -onion inválido: "%s"</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> - <translation type="unfinished">Dirección de -proxy o dominio ' %s' inválido</translation> + <translation type="unfinished">Dirección o nombre de host de -proxy inválido: "%s"</translation> </message> <message> <source>Invalid P2P permission: '%s'</source> @@ -4157,16 +4640,24 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">Importe inválido para %s=<amount>: "%s"</translation> </message> <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation type="unfinished">Importe inválido para -%s=<amount>: "%s"</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation type="unfinished">Máscara de red inválida especificada en -whitelist: "%s"</translation> + </message> + <message> <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Puerto no válido especificado en%s: '%s'</translation> + <translation type="unfinished">Puerto no válido especificado en %s: "%s"</translation> </message> <message> <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no válida %s</translation> + <translation type="unfinished">La entrada preseleccionada no es válida %s</translation> </message> <message> <source>Listening for incoming connections failed (listen returned error %s)</source> - <translation type="unfinished">Fallo en la escucha para conexiones entrantes (la escucha devolvió el error %s)</translation> + <translation type="unfinished">Fallo al escuchar conexiones entrantes (la escucha devolvió el error %s)</translation> </message> <message> <source>Loading P2P addresses…</source> @@ -4174,7 +4665,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Loading banlist…</source> - <translation type="unfinished">Cargando lista de bloqueos...</translation> + <translation type="unfinished">Cargando lista de prohibiciones...</translation> </message> <message> <source>Loading block index…</source> @@ -4186,13 +4677,17 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Missing amount</source> - <translation type="unfinished">Falta la cantidad</translation> + <translation type="unfinished">Falta el importe</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 la transacción</translation> </message> <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation type="unfinished">Se necesita especificar un puerto con -whitebind: "%s"</translation> + </message> + <message> <source>No addresses available</source> <translation type="unfinished">No hay direcciones disponibles</translation> </message> @@ -4202,11 +4697,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Not found pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no encontrada%s</translation> + <translation type="unfinished">La entrada preseleccionada no se encontró %s</translation> </message> <message> <source>Not solvable pre-selected input %s</source> - <translation type="unfinished">Entrada preseleccionada no solucionable %s</translation> + <translation type="unfinished">La entrada preseleccionada no se puede solucionar %s</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -4218,7 +4713,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Pruning blockstore…</source> - <translation type="unfinished">Podando almacén de bloques…</translation> + <translation type="unfinished">Podando almacenamiento 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> @@ -4250,7 +4749,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished">Transacción falló</translation> + <translation type="unfinished">Fallo al firmar la transacción</translation> </message> <message> <source>Specified -walletdir "%s" does not exist</source> @@ -4278,7 +4777,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The source code is available from %s.</source> - <translation type="unfinished">El código fuente esta disponible desde %s.</translation> + <translation type="unfinished">El código fuente está disponible en %s.</translation> </message> <message> <source>The specified config file %s does not exist</source> @@ -4286,15 +4785,23 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">El monto de la transacción es demasiado pequeño para pagar la comisión</translation> + <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">La billetera evitará pagar menos que 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 tarifa mÃnima a pagar en cada transacción.</translation> + <translation type="unfinished">Esta es la comisión mÃnima de transacción que pagas 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 tarifa a pagar si realizas una transacción.</translation> + <translation type="unfinished">Esta es la comisión de transacción que pagarás si envÃas una transacción.</translation> </message> <message> <source>Transaction %s does not belong to this wallet</source> @@ -4302,11 +4809,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished">Monto de la transacción muy pequeño</translation> + <translation type="unfinished">El importe de la transacción es demasiado pequeño</translation> </message> <message> <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Los montos de la transacción no debe ser negativo</translation> + <translation type="unfinished">Los importes de la transacción no pueden ser negativos</translation> </message> <message> <source>Transaction change output index out of range</source> @@ -4314,7 +4821,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Transaction must have at least one recipient</source> - <translation type="unfinished">La transacción debe tener al menos un destinatario</translation> + <translation type="unfinished">La transacción debe incluir al menos un destinatario</translation> </message> <message> <source>Transaction needs a change address, but we can't generate it.</source> @@ -4361,6 +4868,10 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> <translation type="unfinished">No se puede analizar -maxuploadtarget: "%s"</translation> </message> <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation type="unfinished">No se puede iniciar el servidor HTTP. Consulta el registro de depuración para obtener información.</translation> + </message> + <message> <source>Unable to unload the wallet before migrating</source> <translation type="unfinished">No se puede descargar la billetera antes de la migración</translation> </message> @@ -4378,7 +4889,7 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation type="unfinished">La red especificada en -onlynet '%s' es desconocida</translation> + <translation type="unfinished">Se desconoce la red especificada en -onlynet: "%s"</translation> </message> <message> <source>Unknown new rules activated (versionbit %i)</source> @@ -4386,15 +4897,15 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Nivel de acceso global %s = %s no mantenido. Los valores válidos son: %s.</translation> + <translation type="unfinished">El nivel de registro global %s=%s no es compatible. Valores válidos: %s.</translation> </message> <message> <source>Wallet file creation failed: %s</source> - <translation type="unfinished">Creación errónea del fichero monedero: %s</translation> + <translation type="unfinished">Error al crear el archivo de la billetera: %s</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates no está mantenido en el encadenamiento %s.</translation> + <translation type="unfinished">acceptstalefeeestimates no se admite en la cadena %s.</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> @@ -4402,11 +4913,11 @@ No se puede restaurar la copia de seguridad de la billetera.</translation> </message> <message> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Error: no pudo agregar tx de solo vigÃa %s para monedero de solo vigÃa</translation> + <translation type="unfinished">Error: No se pudo agregar la transacción %s a la billetera solo de observación.</translation> </message> <message> <source>Error: Could not delete watchonly transactions. </source> - <translation type="unfinished">Error: no se pudieron eliminar las transacciones de watchonly.</translation> + <translation type="unfinished">Error: No se pudieron eliminar las transacciones solo de observación</translation> </message> <message> <source>User Agent comment (%s) contains unsafe characters.</source> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index 5da96344e5..2c83bc082f 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -2,6 +2,10 @@ <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> @@ -9,6 +13,10 @@ <source>Copy the currently selected address to the system clipboard</source> <translation type="unfinished">Ú©Ù¾ÛŒ آدرسی Ú©Ù‡ اکنون انتخاب کردید در کلیپ بورد سیستم</translation> </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">آدرس‌های گیرنده - %1</translation> + </message> </context> <context> <name>AskPassphraseDialog</name> @@ -519,6 +527,14 @@ <translation type="unfinished">همه‌ی کی٠پول‌ها را ببند</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">انتقال کی٠پول</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">انتقال یک کی٠پول</translation> + </message> + <message> <source>default wallet</source> <translation type="unfinished">کی٠پول پیش Ùرض  </translation> @@ -599,6 +615,14 @@ <translation type="unfinished">پیش‌همگام‌سازی سرصÙØه‌ها (%1%)…</translation> </message> <message> + <source>Error creating wallet</source> + <translation type="unfinished">خطا در ایجاد کی٠پول</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">نمی‌توان کی٠پول جدیدی ایجاد کرد، نرم‌اÙزار بدون پشتیبانی sqlite کامپایل شده است (برای کی٠پول‌های توصیÙ‌گر این ویژگی لازم است)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">خطا: %1</translation> </message> @@ -815,6 +839,37 @@ </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">انتقال کی٠پول</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">آیا برای انتقال کی٠پول مطمئن هستید <i>%1</i>ØŸ</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">انتقال کی٠پول</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">در Øال انتقال کی٠پول <b>%1</b>... </translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">کی٠پول '%1' با موÙقیت منتقل گردید.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">انتقال موÙÙ‚ نبود</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">انتقال موÙÙ‚ بود</translation> + </message> +</context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -892,6 +947,10 @@  </translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">تنها یک قدم با ایجاد کی٠پول جدیدتان Ùاصله دارید!</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">نام کی٠پول</translation> </message> @@ -1844,6 +1903,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">انتخاب همتا یا جÙت برای جزییات اطلاعات</translation> </message> <message> + <source>Transport</source> + <translation type="unfinished">جابه‌جایی</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">نسخه</translation> </message> @@ -3431,6 +3494,10 @@ The wallet might have been tampered with or created with malicious intent. </translation> </message> <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">تايید بلوک دچار قطعی شد</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation type="unfinished">Ú©Ù¾ÛŒ رایت (C) %i-%i</translation> </message> @@ -3471,6 +3538,10 @@ The wallet might have been tampered with or created with malicious intent. <translation type="unfinished">خطا در بازکردن پایگاه داده بلاک block</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">خطا در خواندن Ùایل تنظیمات: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">خواندن از پایگاه داده با خطا مواجه شد,در Øال خاموش شدن.</translation> </message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index cbf81afdb2..5139486348 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -90,6 +90,14 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Virhe tallentaessa osoitelistaa kohteeseen %1. Yritä uudelleen.</translation> </message> <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">Osoitteiden lähettäminen - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Vastaanottava osoite - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Vienti epäonnistui</translation> </message> @@ -291,6 +299,18 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">tuntematon</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">upotettu "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Järjestelmän oletuskirjasin "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Mukautettu…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Määrä</translation> </message> @@ -303,6 +323,12 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Reitittämätön</translation> </message> <message> + <source>Onion</source> + <comment>network name</comment> + <extracomment>Name of Tor network in peer info</extracomment> + <translation type="unfinished">Sipuli</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">Sisääntuleva</translation> @@ -313,11 +339,26 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Ulosmenevä</translation> </message> <message> + <source>Full Relay</source> + <extracomment>Peer connection type that relays all network information.</extracomment> + <translation type="unfinished">Täysi Rele</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">Lohko Rele</translation> + </message> + <message> <source>Manual</source> <extracomment>Peer connection type established manually through one of several methods.</extracomment> <translation type="unfinished">Manuaali</translation> </message> <message> + <source>Feeler</source> + <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> + <translation type="unfinished">Tunturi</translation> + </message> + <message> <source>Address Fetch</source> <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> <translation type="unfinished">Osoitteen haku</translation> @@ -616,6 +657,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Lataa osittain allekirjoitettu bitcoin-siirtotapahtuma</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Lataa PSBT &leikepöydältä…</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Lataa osittain allekirjoitettu bitcoin-siirtotapahtuma leikepöydältä</translation> </message> @@ -666,6 +711,14 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Sulje kaikki lompakot</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Siirrä lompakko</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Siirrä lompakko</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished">Näytä %1 ohjeet saadaksesi listan mahdollisista Bitcoinin komentorivivalinnoista</translation> </message> @@ -725,6 +778,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <source>&Hide</source> <translation type="unfinished">&Piilota</translation> </message> + <message> + <source>S&how</source> + <translation type="unfinished">N&äytä</translation> + </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> @@ -754,6 +811,18 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Ota verkkotoiminta käyttöön</translation> </message> <message> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Esi synkronoidaan otsikot (%1%)…</translation> + </message> + <message> + <source>Error creating wallet</source> + <translation type="unfinished">Virhe luodessa lompakkoa</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">Uutta lompakkoa ei voi luoda, ohjelmisto on käännetty ilman sqlite-tukea (tarvitaan kuvauslompakoissa)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Virhe: %1</translation> </message> @@ -920,6 +989,14 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Kopioi &määrä</translation> </message> <message> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">Kopioi tapahtumatunnus &ID ja tulosindeksi</translation> + </message> + <message> + <source>L&ock unspent</source> + <translation type="unfinished">L&kitse käyttämättömät</translation> + </message> + <message> <source>&Unlock unspent</source> <translation type="unfinished">&Avaa käyttämättömien lukitus</translation> </message> @@ -1007,6 +1084,57 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Siirrä lompakko</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Oletko varma, että haluat siirtää lompakon <i>%1</i>?</translation> + </message> + <message> + <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> + <translation type="unfinished"> +Migrer le portefeuille convertira ce portefeuille en un ou plusieurs portefeuilles de descripteurs. Une nouvelle sauvegarde du portefeuille devra être effectuée. +Si ce portefeuille contient des scripts watchonly, un nouveau portefeuille sera créé avec ces scripts watchonly. +Si ce portefeuille contient des scripts solvables mais non surveillés, un portefeuille différent et nouveau sera créé avec ces scripts. + +Le processus de migration créera une sauvegarde du portefeuille avant de migrer. Ce fichier de sauvegarde sera nommé -.legacy.bak et se trouvera dans le répertoire de ce portefeuille. En cas de migration incorrecte, la sauvegarde peut être restaurée avec la fonctionnalité "Restaurer le portefeuille". + + +Lompakon siirtäminen muuntaa tämän lompakon yhdeksi tai useammaksi kuvailluksi lompakoksi. Uusi lompakon varmuuskopio on tehtävä. +Jos tämä lompakko sisältää vain katseltavia skriptejä, luodaan uusi lompakko, joka sisältää nämä katseltavat skriptit. +Jos tämä lompakko sisältää ratkaistavia mutta ei katsottuja skriptejä, luodaan eri ja uusi lompakko, joka sisältää nämä skriptit. + +Siirtoprosessi luo varmuuskopion lompakosta ennen siirtoa. Tämä varmuuskopiotiedosto nimetään -.legacy.bak ja se löytyy tämän lompakon hakemistosta. Virheellisen siirron sattuessa varmuuskopio voidaan palauttaa "Palauta lompakko" -toiminnolla.</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Siirrä lompakko</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">Siirretään lompakkoa <b>%1</b>...</translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">Lompakko '%1' siirrettiin onnistuneesti.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">Siirto epäonnistui</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">Siirto onnistui</translation> + </message> +</context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -1048,7 +1176,17 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment> <translation type="unfinished">Lompakon palauttaminen epäonnistui</translation> </message> - </context> + <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">Palauta lompakkovaroitus</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">Palauta lompakkoviesti</translation> + </message> +</context> <context> <name>WalletController</name> <message> @@ -1075,6 +1213,14 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Luo lompakko</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Olet yhden askeleen päässä uuden lompakon luomisesta!</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">Anna nimi ja ota halutessasi käyttöön lisäasetukset</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Lompakon nimi</translation> </message> @@ -1211,8 +1357,8 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB vapaata tilaa</numerusform> + <numerusform>%n GB vapaata tilaa</numerusform> </translation> </message> <message numerus="yes"> @@ -1294,6 +1440,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Tämä alustava synkronointi on erittäin vaativa ja saattaa tuoda esiin laiteongelmia, joita ei aikaisemmin ole havaittu. Aina kun ajat %1:n, jatketaan siitä kohdasta, mihin viimeksi jäätiin.</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">Kun napsautat OK, %1 alkaa ladata ja käsitellä koko %4 lohkoketjun (%2 GB) alkaen ensimmäisistä tapahtumista %3 kun %4 alun perin käynnistetty.</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">Vaikka olisitkin valinnut rajoittaa lohkoketjun tallennustilaa (karsinnalla), täytyy historiatiedot silti ladata ja käsitellä, mutta ne poistetaan jälkikäteen levytilan säästämiseksi.</translation> </message> @@ -1390,7 +1540,11 @@ 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> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Tuntematon. Esi synkronointi otsikot (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -1434,6 +1588,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Säikeiden määrä skriptien &varmistuksessa</translation> </message> <message> + <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">Täysi polku %1 yhteensopivaan komentosarjaan (esim. C:\Downloads\hwi.exe tai /Users/you/Downloads/hwi.py). Varo: haittaohjelmat voivat varastaa kolikkosi!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">IP osoite proxille (esim. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -1446,6 +1604,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Minimoi ikkuna ohjelman sulkemisen sijasta kun ikkuna suljetaan. Kun tämä asetus on käytössä, ohjelma suljetaan vain valittaessa valikosta Poistu.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Fontti Yleiskatsaus-välilehdellä:</translation> + </message> + <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">Tässä valintaikkunassa asetetut asetukset ohitetaan komentorivillä:</translation> </message> @@ -1487,6 +1649,11 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Tietokannan välimuistin enimmäiskoko. Suurempi välimuisti voi nopeuttaa synkronointia, mutta sen jälkeen hyöty ei ole enää niin merkittävä useimmissa käyttötapauksissa. Välimuistin koon pienentäminen vähentää muistin käyttöä. Käyttämätön mempool-muisti jaetaan tätä välimuistia varten.</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">Aseta komentosarjan vahvistusketjujen määrä. Negatiiviset arvot vastaavat niiden ytimien määrää, jotka haluat jättää järjestelmälle vapaiksi.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished">(0 = auto, <0 = jätä näin monta ydintä vapaaksi)</translation> </message> @@ -1505,6 +1672,16 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">&Lompakko</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">Määritetäänkö summasta vähennysmaksu oletusarvoksi vai ei.</translation> + </message> + <message> + <source>Subtract &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">Vähennä &maksu oletuksena summasta</translation> + </message> + <message> <source>Expert</source> <translation type="unfinished">Expertti</translation> </message> @@ -1526,10 +1703,19 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Aktivoi &PSBT kontrollit</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">Näytetäänkö PSBT-ohjaimet.</translation> + </message> + <message> <source>External Signer (e.g. hardware wallet)</source> <translation type="unfinished">Ulkopuolinen allekirjoittaja (esim. laitelompakko)</translation> </message> <message> + <source>&External signer script path</source> + <translation type="unfinished">&Ulkoisen allekirjoittajan komentosarjapolku</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">Avaa Bitcoin-asiakasohjelman portti reitittimellä automaattisesti. Tämä toimii vain, jos reitittimesi tukee UPnP:tä ja se on käytössä.</translation> </message> @@ -1622,6 +1808,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Valitse mitä yksikköä käytetään ensisijaisesti bitcoin-määrien näyttämiseen.</translation> </message> <message> + <source>&Third-party transaction URLs</source> + <translation type="unfinished">&Kolmannen osapuolen tapahtuma-URL-osoitteet</translation> + </message> + <message> <source>Whether to show coin control features or not.</source> <translation type="unfinished">Näytetäänkö kolikkokontrollin ominaisuuksia vai ei</translation> </message> @@ -1661,6 +1851,11 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">Ohjelman uudelleenkäynnistys aktivoi muutokset.</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">Nykyiset asetukset varmuuskopioidaan klo"%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">Asiakasohjelma sammutetaan. Haluatko jatkaa?</translation> @@ -1701,6 +1896,13 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio </message> </context> <context> + <name>OptionsModel</name> + <message> + <source>Could not read setting "%1", %2.</source> + <translation type="unfinished">Ei voinut luke asetusta "%1", %2.</translation> + </message> +</context> +<context> <name>OverviewPage</name> <message> <source>Form</source> @@ -1782,6 +1984,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <context> <name>PSBTOperationsDialog</name> <message> + <source>PSBT Operations</source> + <translation type="unfinished">PSBT-toiminnot</translation> + </message> + <message> <source>Sign Tx</source> <translation type="unfinished">Allekirjoita Tx</translation> </message> @@ -1855,6 +2061,10 @@ Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translatio <translation type="unfinished">PSBT (osittain tallennettu bitcoin-siirto) tallennettiin levylle.</translation> </message> <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">Lähettää %1 kohteelle %2</translation> + </message> + <message> <source>own address</source> <translation type="unfinished">oma osoite</translation> </message> @@ -1960,6 +2170,11 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Vertainen</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">Ikä</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">Suunta</translation> @@ -2127,10 +2342,34 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Valitse vertainen eriteltyjä tietoja varten.</translation> </message> <message> + <source>The transport layer version: %1</source> + <translation type="unfinished">Kuljetuskerroksen versio: %1</translation> + </message> + <message> + <source>Transport</source> + <translation type="unfinished">Kuljetus</translation> + </message> + <message> + <source>The BIP324 session ID string in hex, if any.</source> + <translation type="unfinished">BIP324-istunnon tunnusmerkkijono heksadesimaalimuodossa, jos sellainen on.</translation> + </message> + <message> + <source>Session ID</source> + <translation type="unfinished">Istunnon tunniste</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Versio</translation> </message> <message> + <source>Whether we relay transactions to this peer.</source> + <translation type="unfinished">Välitämmekö tapahtumat tälle vertaiselle.</translation> + </message> + <message> + <source>Transaction Relay</source> + <translation type="unfinished">Siirtokulu</translation> + </message> + <message> <source>Starting Block</source> <translation type="unfinished">Alkaen lohkosta</translation> </message> @@ -2155,11 +2394,36 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Kartoitettu 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">Välitämmekö osoitteet tälle vertaiselle.</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">Osoitevälitys</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">Tältä vertaiselta käsiteltyjen osoitteiden kokonaismäärä (ei sisällä osoitteita, jotka hylättiin nopeusrajoituksen vuoksi).</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">Tältä vertaiselta saatujen osoitteiden kokonaismäärä, jotka hylättiin (ei käsitelty) nopeusrajoituksen vuoksi.</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">Käsitellyt osoitteet</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">Osoitteiden määrärajoitus</translation> + </message> + <message> <source>User Agent</source> <translation type="unfinished">Käyttöliittymä</translation> </message> @@ -2220,6 +2484,11 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Viimeisin lohko</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">Kulunut aika siitä, kun tältä vertaiskumppanilta vastaanotettiin muistiomme hyväksytty uusi tapahtuma.</translation> + </message> + <message> <source>Last Send</source> <translation type="unfinished">Viimeisin lähetetty</translation> </message> @@ -2289,6 +2558,53 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Saapuva: vertaisen aloittama</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">Lähtevä täysi välitys: oletus</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: ei välitä tapahtumia tai osoitteita</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: lyhytaikainen, osoitteiden testaamiseen</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">Lähtevän osoitteen haku: lyhytkestoinen, osoitteiden pyytämiseen</translation> + </message> + <message> + <source>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">havaitseminen: vertaiskumppani voi olla v1 tai v2</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: salaamaton, selväkielinen siirtoprotokolla</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: BIP324-salattu siirtoprotokolla</translation> + </message> + <message> + <source>we selected the peer for high bandwidth relay</source> + <translation type="unfinished">valitsimme korkean kaistanleveyden releen vertaislaitteen</translation> + </message> + <message> + <source>the peer selected us for high bandwidth relay</source> + <translation type="unfinished">vertaiskumppani valitsi meidät suuren kaistanleveyden välitykseen</translation> + </message> + <message> + <source>no high bandwidth relay selected</source> + <translation type="unfinished">suuren kaistanleveyden relettä ei ole valittu</translation> + </message> + <message> <source>Ctrl+=</source> <extracomment>Secondary shortcut to increase the RPC console font size.</extracomment> <translation type="unfinished">Ctrl+-</translation> @@ -2307,6 +2623,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">1 &tunti</translation> </message> <message> + <source>1 d&ay</source> + <translation type="unfinished">1 p&ivä</translation> + </message> + <message> <source>1 &week</source> <translation type="unfinished">1 &viikko</translation> </message> @@ -2315,6 +2635,11 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">1 &vuosi</translation> </message> <message> + <source>&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">&Kopioi IP/verkkopeite</translation> + </message> + <message> <source>&Unban</source> <translation type="unfinished">&Poista esto</translation> </message> @@ -2463,6 +2788,27 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Kopioi &määrä</translation> </message> <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Base58 (Vanha)</translation> + </message> + <message> + <source>Not recommended due to higher fees and less protection against typos.</source> + <translation type="unfinished">Ei suositella korkeampien maksujen ja heikomman suojan kirjoitusvirheitä vastaan.</translation> + </message> + <message> + <source>Generates an address compatible with older wallets.</source> + <translation type="unfinished">Luo osoitteen, joka on yhteensopiva vanhempien lompakoiden kanssa.</translation> + </message> + <message> + <source>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> + <translation type="unfinished"> +Luo natiivin segwit-osoitteen (BIP-173). Jotkin vanhat lompakot eivät tue sitä.</translation> + </message> + <message> + <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> + <translation type="unfinished">Bech32m (BIP-350) on päivitys Bech32, mutta lompakkojen tuki on edelleen rajallinen.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation type="unfinished">Lompakkoa ei voitu avata.</translation> </message> @@ -2660,6 +3006,15 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished"> Piilota siirtomaksuasetukset</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">Määritä mukautettu maksu per kB (1 000 tavua) tapahtuman virtuaalikoosta. + +Huom: Koska maksu lasketaan per tavu, "100 satoshin per kB" maksunopeus 500 virtuaalitavun (puolet 1 kB +) tapahtumakoolle johtaisi lopulta vain 50 satoshin maksuun.</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">Mikäli lohkoissa ei ole tilaa kaikille siirtotapahtumille, voi louhijat sekä välittävät solmut pakottaa vähimmäispalkkion. Tämän vähimmäispalkkion maksaminen on täysin OK, mutta huomaa, että se saattaa johtaa siihen, ettei siirto vahvistu koskaan, jos bitcoin-siirtoja on enemmän kuin mitä verkko pystyy käsittelemään.</translation> </message> @@ -2668,6 +3023,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Liian alhainen maksu saattaa johtaa siirtoon, joka ei koskaan vahvistu (lue työkaluohje)</translation> </message> <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> + <translation type="unfinished">(Älykäs maksu ei ole vielä alustettu. Tämä vie yleensä muutaman lohkon...)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation type="unfinished">Vahvistusajan tavoite:</translation> </message> @@ -2763,6 +3122,11 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Ulkopuolista allekirjoittajaa ei löydy</translation> </message> <message> + <source>External signer failure</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">Ulkoisen allekirjoittajan virhe</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">Tallenna siirtotiedot</translation> </message> @@ -2794,11 +3158,20 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Ole hyvä ja tarkista siirtoehdotuksesi. Tämä luo osittain allekirjoitetun Bitcoin-siirron (PBST), jonka voit tallentaa tai kopioida ja sitten allekirjoittaa esim. verkosta irrannaisella %1-lompakolla tai PBST-yhteensopivalla laitteistolompakolla.</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 lompakosta '%2'</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">Haluatko luoda tämän siirtotapahtuman?</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">Ole hyvä ja tarkista tapahtumasi. Voit luoda ja lähettää tämän tapahtuman tai luoda osittain allekirjoitetun Bitcoin-tapahtuman (PSBT), jonka voit tallentaa tai kopioida ja allekirjoittaa esimerkiksi offline-ympäristössä%1lompakkoosi tai PSBT-yhteensopivalla laitteistolompakolla.</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">Tarkistathan siirtosi.</translation> @@ -2816,6 +3189,20 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Yhteensä</translation> </message> <message> + <source>Unsigned Transaction</source> + <comment>PSBT copied</comment> + <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> + <translation type="unfinished">Allekirjoittamaton Siirto</translation> + </message> + <message> + <source>The PSBT has been copied to the clipboard. You can also save it.</source> + <translation type="unfinished">PSBT on kopioitu leikepöydälle. Voit myös tallentaa sen.</translation> + </message> + <message> + <source>PSBT saved to disk</source> + <translation type="unfinished">PSBT tallennettu levylle</translation> + </message> + <message> <source>Confirm send coins</source> <translation type="unfinished">Vahvista kolikoiden lähetys</translation> </message> @@ -3111,6 +3498,16 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">ristiriidassa maksutapahtumalle, jolla on %1 varmistusta</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/vahvistamatonta, memory poolissa</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/vahvistamatonta, ei memory poolissa</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> @@ -3225,6 +3622,10 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Ulostulon indeksi</translation> </message> <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (Sertifikaattia ei ole todennettu)</translation> + </message> + <message> <source>Merchant</source> <translation type="unfinished">Kauppias</translation> </message> @@ -3434,6 +3835,35 @@ Jos saat tämän virheen, pyydä kauppiasta antamaan BIP21-yhteensopiva URI.</tr <translation type="unfinished">Kopio transaktio &ID</translation> </message> <message> + <source>Copy &raw transaction</source> + <translation type="unfinished">Kopioi &raaka tapahtuma</translation> + </message> + <message> + <source>Copy full transaction &details</source> + <translation type="unfinished">Kopioi koko tapahtuma &tiedot</translation> + </message> + <message> + <source>&Show transaction details</source> + <translation type="unfinished">&Näytä tapahtuman tiedot</translation> + </message> + <message> + <source>Increase transaction &fee</source> + <translation type="unfinished">Lisää tapahtuman &kuluja</translation> + </message> + <message> + <source>A&bandon transaction</source> + <translation type="unfinished">H&ylkää tapahtuma</translation> + </message> + <message> + <source>&Edit address label</source> + <translation type="unfinished">&Muokkaa osoitekenttää</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">Näytä %1</translation> + </message> + <message> <source>Export Transaction History</source> <translation type="unfinished">Vie rahansiirtohistoria</translation> </message> @@ -3562,6 +3992,11 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Uusi palkkio:</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"> +Varoitus: Tämä voi maksaa ylimääräisen maksun vähentämällä vaihtotuloja tai lisäämällä tuloja tarvittaessa. Se voi lisätä uuden vaihtotulojen, jos sellaista ei jo ole. Nämä muutokset voivat mahdollisesti vuotaa yksityisyyttä.</translation> + </message> + <message> <source>Confirm fee bump</source> <translation type="unfinished">Vahvista palkkion korotus</translation> </message> @@ -3574,6 +4009,11 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">PSBT kopioitu</translation> </message> <message> + <source>Copied to clipboard</source> + <comment>Fee-bump PSBT saved</comment> + <translation type="unfinished">Kopioi leikepöydälle</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Siirtoa ei voida allekirjoittaa.</translation> </message> @@ -3641,6 +4081,11 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">%s on vioittunut. Yritä käyttää lompakkotyökalua bitcoin-wallet pelastaaksesi sen tai palauttaa varmuuskopio.</translation> </message> <message> + <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> + <translation type="unfinished">%s virheellinen -assumeutxo-snapshot-tila. Tämä viittaa laitteistoon liittyvään ongelmaan, ohjelmistovirheeseen tai huonoon ohjelmistomuutokseen, joka on sallinut virheellisen snapshotin lataamisen. Tämän seurauksena solmu sulkeutuu ja lopettaa kaiken sen tilan käytön, joka perustui snapshottiin, ja nollaa lohkokorkeuden%darvoon%d. Seuraavassa uudelleenkäynnistyksessä solmu jatkaa synkronointia kohdasta%d  +ilman, että käytetään mitään snapshot-tietoja. Ilmoita tästä tapauksesta osoitteeseen%s, mukaan lukien se, miten sait snapshotin. Virheellinen snapshot-tilatiedosto jätetään levylle, jos se on hyödyllinen ongelman diagnosoinnissa, joka aiheutti tämän virheen.</translation> + </message> + <message> <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> <translation type="unfinished">Ei voida alentaa lompakon versiota versiosta %i versioon %i. Lompakon versio pysyy ennallaan.</translation> </message> @@ -3753,6 +4198,22 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Hakemistoon '%s' ei voida kirjoittaa. Tarkista käyttöoikeudet.</translation> </message> <message> + <source> +Unable to cleanup failed migration</source> + <translation type="unfinished"> +Epäonnistuneen migraation siivoaminen epäonnistui</translation> + </message> + <message> + <source> +Unable to restore backup of wallet.</source> + <translation type="unfinished"> +Ei voinut palauttaa lompakon varmuuskopiota..</translation> + </message> + <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">Lohkon vahvistus keskeytettiin</translation> + </message> + <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished">Konfigurointiasetuksen %s käyttöön vain %s -verkossa, kun osassa [%s].</translation> </message> @@ -3825,6 +4286,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Virhe avattaessa lohkoindeksiä</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">Virhe luettaessa asetustiedostoa 1%s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">Virheitä tietokantaa luettaessa, ohjelma pysäytetään.</translation> </message> @@ -3853,6 +4318,30 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">virhe: Puuttuva tarkistussumma</translation> </message> <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">Virhe: Ei %s osoitteita saatavilla.</translation> + </message> + <message> + <source>Error: This wallet already uses SQLite</source> + <translation type="unfinished">Virhe: Tämä lompakko käyttää jo SQLite:ä</translation> + </message> + <message> + <source>Error: Unable to make a backup of your wallet</source> + <translation type="unfinished">Virhe: Lompakon varmuuskopion luominen epäonnistui</translation> + </message> + <message> + <source>Error: Unable to read all records in the database</source> + <translation type="unfinished">Virhe: Kaikkien tietueiden lukeminen tietokannasta ei onnistunut</translation> + </message> + <message> + <source>Error: Unable to write record to new wallet</source> + <translation type="unfinished">Virhe: Tiedon kirjoittaminen lompakkoon epäonnistui</translation> + </message> + <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Virhe: osoitekirjan kopiointi epäonnistui lompakolle %s</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Ei onnistuttu kuuntelemaan missään portissa. Käytä -listen=0 jos haluat tätä.</translation> </message> @@ -3861,10 +4350,18 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Lompakkoa ei voitu tarkastaa alustuksen yhteydessä.</translation> </message> <message> + <source>Failed to start indexes, shutting down..</source> + <translation type="unfinished">Indeksien käynnistäminen epäonnistui, sammutetaan..</translation> + </message> + <message> <source>Failed to verify database</source> <translation type="unfinished">Tietokannan todennus epäonnistui</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Siirron poistaminen epäonnistui: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">Kulutaso (%s) on alempi, kuin minimikulutasoasetus (%s)</translation> </message> @@ -3885,6 +4382,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Alustava järkevyyden tarkistus epäonnistui. %s sulkeutuu.</translation> </message> <message> + <source>Insufficient dbcache for block verification</source> + <translation type="unfinished">Riittämätön dbcache lohkon vahvistukseen</translation> + </message> + <message> <source>Insufficient funds</source> <translation type="unfinished">Lompakon saldo ei riitä</translation> </message> @@ -3905,6 +4406,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Virheellinen P2P-lupa: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Virheellinen määrä %s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Virheellinen määrä -%s=<amount>: '%s'</translation> </message> @@ -3913,6 +4418,18 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Kelvoton verkkopeite määritelty argumentissa -whitelist: '%s'</translation> </message> <message> + <source>Invalid port specified in %s: '%s'</source> + <translation type="unfinished">Virheellinen portti määritetty %s: '%s'</translation> + </message> + <message> + <source>Invalid pre-selected input %s</source> + <translation type="unfinished">Virheellinen esivalittu syöte %s</translation> + </message> + <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">Saapuvien yhteyksien kuuntelu epäonnistui (kuuntelu palasi virheen %s)</translation> + </message> + <message> <source>Loading P2P addresses…</source> <translation type="unfinished">Ladataan P2P-osoitteita...</translation> </message> @@ -3933,6 +4450,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Puuttuva summa</translation> </message> <message> + <source>Missing solving data for estimating transaction size</source> + <translation type="unfinished">Ratkaisutiedot puuttuvat tapahtuman koon arvioimiseksi</translation> + </message> + <message> <source>Need to specify a port with -whitebind: '%s'</source> <translation type="unfinished">Pitää määritellä portti argumentilla -whitebind: '%s'</translation> </message> @@ -3945,6 +4466,14 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Ei tarpeeksi tiedostomerkintöjä vapaana.</translation> </message> <message> + <source>Not found pre-selected input %s</source> + <translation type="unfinished">Esivalittua tuloa ei löydy %s</translation> + </message> + <message> + <source>Not solvable pre-selected input %s</source> + <translation type="unfinished">Ei ratkaistavissa esivalittu tulo%s</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Karsintaa ei voi toteuttaa negatiivisella arvolla.</translation> </message> @@ -4009,6 +4538,14 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Määrättyä lohkohakemistoa "%s" ei ole olemassa.</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">Määritettyä tietohakemistoa %s ei ole olemassa.</translation> + </message> + <message> + <source>Starting network threads…</source> + <translation type="unfinished">Aloitetaan verkkosäikeitä…</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Lähdekoodi löytyy %s.</translation> </message> @@ -4037,6 +4574,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Tämä on se siirtomaksu, jonka maksat, mikäli lähetät siirron.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Tapahtuma %s ei kuulu tähän lompakkoon</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Siirtosumma liian pieni</translation> </message> @@ -4045,14 +4586,26 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Lähetyksen siirtosumman tulee olla positiivinen</translation> </message> <message> + <source>Transaction change output index out of range</source> + <translation type="unfinished">Tapahtuman muutoksen tulosindeksi on alueen ulkopuolella</translation> + </message> + <message> <source>Transaction must have at least one recipient</source> <translation type="unfinished">Lähetyksessä tulee olla ainakin yksi vastaanottaja</translation> </message> <message> + <source>Transaction needs a change address, but we can't generate it.</source> + <translation type="unfinished">Tapahtuma vaatii osoitteenmuutoksen, mutta emme voi luoda sitä.</translation> + </message> + <message> <source>Transaction too large</source> <translation type="unfinished">Siirtosumma liian iso</translation> </message> <message> + <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> + <translation type="unfinished">Ei voida varata muistia kohteelle %sMiB</translation> + </message> + <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Kytkeytyminen kohteeseen %s ei onnistunut tällä tietokonella (kytkeytyminen palautti virheen %s)</translation> </message> @@ -4065,6 +4618,10 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">PID-tiedostoa '%s' ei voitu luoda: %s</translation> </message> <message> + <source>Unable to find UTXO for external input</source> + <translation type="unfinished">Ulkoisen tulon UTXO ei löydy</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation type="unfinished">Alkuavaimia ei voi luoda</translation> </message> @@ -4077,10 +4634,18 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Ei pystytä avaamaan %s kirjoittamista varten</translation> </message> <message> + <source>Unable to parse -maxuploadtarget: '%s'</source> + <translation type="unfinished">Ei voi lukea -maxuploadtarget: '%s'</translation> + </message> + <message> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished">HTTP-palvelinta ei voitu käynnistää. Katso debug-lokista lisätietoja.</translation> </message> <message> + <source>Unable to unload the wallet before migrating</source> + <translation type="unfinished">Lompakon lataus epäonnistui ennen siirtoa</translation> + </message> + <message> <source>Unknown -blockfilterindex value %s.</source> <translation type="unfinished">Tuntematon -lohkosuodatusindeksiarvo %s.</translation> </message> @@ -4101,6 +4666,14 @@ Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. <translation type="unfinished">Tuntemattomia uusia sääntöjä aktivoitu (versiobitti %i)</translation> </message> <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Lompakon luominen epäonnistui: %s</translation> + </message> + <message> + <source>acceptstalefeeestimates is not supported on %s chain.</source> + <translation type="unfinished">hyväksyttyjä ilmaisia ​​arvioita ei tueta %s ketju.</translation> + </message> + <message> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished">Lokikategoriaa %s=%s ei tueta.</translation> </message> diff --git a/src/qt/locale/bitcoin_fo.ts b/src/qt/locale/bitcoin_fo.ts index 2d6a543454..20b8db74bd 100644 --- a/src/qt/locale/bitcoin_fo.ts +++ b/src/qt/locale/bitcoin_fo.ts @@ -181,6 +181,10 @@ <translation type="unfinished">Net-virksemi óvirkijað.</translation> </message> <message> + <source>&Receive</source> + <translation type="unfinished">&Móttak</translation> + </message> + <message> <source>Sign &message…</source> <translation type="unfinished">&Undirrita boð</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 796e1affe6..e62e8329f1 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -1137,7 +1137,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>Migration Successful</source> - <translation type="unfinished">Migration réussie</translation> + <translation type="unfinished">La migration est terminée</translation> </message> </context> <context> @@ -1223,7 +1223,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> - <translation type="unfinished">Veuillez fournir un nom et, si désiré, activer toutes les options avancées.</translation> + <translation type="unfinished">Indiquez un nom et, si désiré, activez les options avancées.</translation> </message> <message> <source>Wallet Name</source> @@ -1382,7 +1382,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>Choose data directory</source> - <translation type="unfinished">Choisissez un répertoire de donnée</translation> + <translation type="unfinished">Choisissez le répertoire des données</translation> </message> <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> @@ -1446,7 +1446,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </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">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> + <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, lors du lancement de %4 a été lancé initialement.</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> @@ -1543,7 +1543,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Inconnu. En-têtes de présynchronisation (%1, %2%)...</translation> + <translation type="unfinished">Inconnu. En-têtes de présynchronisation (%1, %2%)…</translation> </message> </context> <context> @@ -1590,7 +1590,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </message> <message> <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">Chemin complet vers un %1 script compatible (par exemple, C:\Downloads\hwi.exe ou /Users/you/Downloads/hwi.py). Attention : les malwares peuvent voler vos pièces !</translation> + <translation type="unfinished">Chemin complet vers un script compatible avec %1 (p. ex. C:\Téléchargements\hwi.exe ou /Utilisateurs/vous/Téléchargements/hwi.py). Attention : des programmes malveillants peuvent voler vos pièces !</translation> </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> @@ -1610,7 +1610,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio </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> + <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> @@ -1862,7 +1862,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio <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 actuels vont être restaurés à "%1".</translation> + <translation type="unfinished">Les paramètres actuels seront sauvegardés à « %1 ».</translation> </message> <message> <source>Client will be shut down. Do you want to proceed?</source> @@ -1908,7 +1908,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio <name>OptionsModel</name> <message> <source>Could not read setting "%1", %2.</source> - <translation type="unfinished">Impossible de lire le paramètre "%1", %2.</translation> + <translation type="unfinished">Impossible de lire le paramètre « %1 », %2.</translation> </message> </context> <context> @@ -1994,7 +1994,7 @@ Le processus de migration créera une sauvegarde du porte-monnaie avant migratio <name>PSBTOperationsDialog</name> <message> <source>PSBT Operations</source> - <translation type="unfinished">Opération PSBT</translation> + <translation type="unfinished">Opération TBSP</translation> </message> <message> <source>Sign Tx</source> @@ -2172,6 +2172,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> @@ -2334,19 +2339,19 @@ If you are receiving this error you should request the merchant provide a BIP21 </message> <message> <source>The transport layer version: %1</source> - <translation type="unfinished">La version de la couche de transport : %1</translation> + <translation type="unfinished">Version de la couche de transport : %1</translation> </message> <message> <source>The BIP324 session ID string in hex, if any.</source> - <translation type="unfinished">La chaîne d'ID de session BIP324 en hexadécimal, le cas échéant.</translation> + <translation type="unfinished">ID hexadécimale de la session BIP324, le cas échéant.</translation> </message> <message> <source>Session ID</source> - <translation type="unfinished">ID de session</translation> + <translation type="unfinished">ID de la session</translation> </message> <message> <source>Whether we relay transactions to this peer.</source> - <translation type="unfinished">Si nous relayons des transactions à ce pair.</translation> + <translation type="unfinished">Relayer ou non des transactions à ce pair.</translation> </message> <message> <source>Transaction Relay</source> @@ -2389,12 +2394,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <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">Nombre total d'adresses reçues de ce pair qui ont été traitées (à l'exclusion des adresses qui ont été abandonnées en raison de la limitation du débit).</translation> + <translation type="unfinished">Nombre total d’adresses reçues de ce pair qui ont été traitées (les adresses abandonnées en raison de la limite du débit sont exclues).</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">Nombre total d'adresses reçues de ce pair qui ont été abandonnées (non traitées) en raison de la limitation du débit.</translation> + <translation type="unfinished">Nombre total d’adresses reçues de ce pair qui ont été abandonnées (non traitées) en raison de la limite du débit.</translation> </message> <message> <source>Addresses Processed</source> @@ -2439,6 +2444,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">La direction et le type de la connexion au pair : %1</translation> </message> <message> + <source>Direction/Type</source> + <translation type="unfinished">Direction ou type</translation> + </message> + <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <translation type="unfinished">Le protocole réseau par lequel ce pair est connecté : IPv4, IPv6, Oignon, I2P ou CJDNS.</translation> </message> @@ -2560,17 +2569,17 @@ If you are receiving this error you should request the merchant provide a BIP21 <message> <source>detecting: peer could be v1 or v2</source> <extracomment>Explanatory text for "detecting" transport type.</extracomment> - <translation type="unfinished">détection : paires pourrait être v1 ou v2</translation> + <translation type="unfinished">détection : les paires pourraient être v1 ou v2</translation> </message> <message> <source>v1: unencrypted, plaintext transport protocol</source> <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">v1: protocole de transport non chiffré en texte clair</translation> + <translation type="unfinished">v1 : protocole de transport non chiffré en texte clair</translation> </message> <message> <source>v2: BIP324 encrypted transport protocol</source> <extracomment>Explanatory text for v2 transport type.</extracomment> - <translation type="unfinished">v2: Protocole de transport chiffré BIP324</translation> + <translation type="unfinished">v2 : protocole de transport chiffré BIP324</translation> </message> <message> <source>we selected the peer for high bandwidth relay</source> @@ -2783,8 +2792,12 @@ Pour plus de précisions sur cette console, tapez %6. <translation type="unfinished">Copier le mont&ant</translation> </message> <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Base58 (ancien)</translation> + </message> + <message> <source>Not recommended due to higher fees and less protection against typos.</source> - <translation type="unfinished">Non recommandé en raison de frais élevés et d'une faible protection contre les fautes de frappe.</translation> + <translation type="unfinished">Non recommandé en raison de frais élevés et d’une protection moindre contre les fautes de frappe.</translation> </message> <message> <source>Generates an address compatible with older wallets.</source> @@ -2843,7 +2856,7 @@ Pour plus de précisions sur cette console, tapez %6. </message> <message> <source>&Verify</source> - <translation type="unfinished">&Vérifier</translation> + <translation type="unfinished">&Confirmer</translation> </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> @@ -3162,6 +3175,12 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <translation type="unfinished">Frais de transaction</translation> </message> <message> + <source>%1 kvB</source> + <comment>PSBT transaction creation</comment> + <extracomment>When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with "virtual size" of the transaction displayed for context</extracomment> + <translation type="unfinished">%1 kvB</translation> + </message> + <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> <translation type="unfinished">Ne signale pas Remplacer-par-des-frais, BIP-125.</translation> </message> @@ -3177,11 +3196,11 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi </message> <message> <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">Le PSBT a été copié dans le presse-papiers. Vous pouvez également le sauvegarder.</translation> + <translation type="unfinished">La TBSP a été copiée dans le presse-papiers. Vous pouvez aussi l’enregistrer.</translation> </message> <message> <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT sauvegardé sur le disque</translation> + <translation type="unfinished">La TBSP a été enregistrée sur le disque</translation> </message> <message> <source>Confirm send coins</source> @@ -3477,12 +3496,12 @@ Note : Les frais étant calculés par octet, un taux de frais de « 100 satoshi <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/non confirmé, dans la pool de mémoire</translation> + <translation type="unfinished">0/non confirmée, dans la réserve de mémoire</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/non confirmé, pas dans la pool de mémoire</translation> + <translation type="unfinished">0/non confirmée, absente de la réserve de mémoire</translation> </message> <message> <source>abandoned</source> @@ -3912,7 +3931,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Fee bump error</source> - <translation type="unfinished">Erreur d’augmentation des frais</translation> + <translation type="unfinished">Erreur de majoration des frais</translation> </message> <message> <source>Increasing transaction fee failed</source> @@ -3941,7 +3960,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Confirm fee bump</source> - <translation type="unfinished">Confirmer l’augmentation des frais</translation> + <translation type="unfinished">Confirmer la majoration des frais</translation> </message> <message> <source>Can't draft transaction.</source> @@ -4025,11 +4044,11 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> - <translation type="unfinished">%s a échoué à valider l'état instantané -assumeutxo. Cela indique un problème matériel, ou un bug dans le logiciel, ou une mauvaise modification du logiciel qui a permis de charger un instantané invalide. En conséquence, le nÅ“ud s'arrêtera et cessera d'utiliser tout état qui a été construit sur l'instantané, réinitialisant la hauteur de la chaîne de %d à %d. Au prochain redémarrage, le nÅ“ud reprendra la synchronisation à partir de %d sans utiliser de données d'instantané. Veuillez signaler cet incident à %s, en précisant comment vous avez obtenu l'instantané. L'état de chaîne d'instantané invalide sera conservé sur le disque au cas où il serait utile pour diagnostiquer le problème qui a causé cette erreur.</translation> + <translation type="unfinished">%s n’a pas réussi à valider l’état de l’instantané -assumeutxo. Cela indique un problème matériel, un bogue logiciel ou une mauvaise modification logicielle qui a permis le chargement d’un instantané invalide. Par conséquent, le nÅ“ud s’arrêtera et cessera d’utiliser tout état fondé sur cet instantané, ce qui réinitialisera à le niveau de la chaîne de %d à %d. Lors du prochain démarrage, la synchronisation reprendra de %d, sans utiliser les données d’un instantané. Signalez cet incident à %s en indiquant comment vous avez obtenu l’instantané. L’état de chaîne de l’instantané invalide sera laissé sur le disque au cas afin d’aider éventuellement à diagnostiquer le problème à l’origine de cette erreur.</translation> </message> <message> <source>%s request to listen on port %u. This port is considered "bad" 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">%s demande d'écouter sur le port %u. Ce port est considéré comme "mauvais" et il est donc peu probable qu'un pair s'y connecte. Voir doc/p2p-bad-ports.md pour plus de détails et une liste complète.</translation> + <translation type="unfinished">%s demande d’écouter sur le port %u. Ce port est considéré comme « mauvais » et il est donc peu probable qu’un pair s’y connecte. Voir doc/p2p-bad-ports.md pour plus de précisions et une liste complète.</translation> </message> <message> <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> @@ -4045,7 +4064,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <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">L'espace disque %s peut ne pas être suffisant pour les fichiers en bloc. Environ %u Go de données seront stockés dans ce répertoire.</translation> + <translation type="unfinished">L’espace disque pourrait être insuffisant sur %s pour accueillir les fichiers de bloc. Environ %u Go de données seront stockés dans ce répertoire.</translation> </message> <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> @@ -4117,7 +4136,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </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 -reindex complet.</translation> + <translation type="unfinished">Le mode d’élagage est incompatible avec -reindex-chainstate. Utilisez plutôt -reindex complet.</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> @@ -4125,7 +4144,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>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.</source> - <translation type="unfinished">La modification de '%s' -> '%s' a échoué. Vous devriez résoudre cela en déplaçant ou en supprimant manuellement le répertoire de snapshot invalide %s, sinon vous rencontrerez la même erreur à nouveau au prochain démarrage.</translation> + <translation type="unfinished">Le renommage de '%s' en '%s' a échoué. Vous devriez résoudre cela en déplaçant ou en supprimant manuellement le répertoire de l’instantané invalide %s, sinon la même erreur surviendra de nouveau lors du prochain démarrage.</translation> </message> <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> @@ -4173,11 +4192,11 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <translation type="unfinished">Niveau de journalisation spécifique à la catégorie non pris en charge %1$s=%2$s. Attendu %1$s=<catégorie>:<niveaudejournal>. Catégories valides : %3$s. Niveaux de journalisation valides : %4$s.</translation> + <translation type="unfinished">Le niveau de journalisation propre à la catégorie n’est pas pris en charge %1$s=%2$s. Attendu %1$s=<category>:<loglevel>. Catégories valides : %3$s. Niveaux de journalisation valides : %4$s.</translation> </message> <message> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> - <translation type="unfinished">Le format de la base de données chainstate n'est pas supporté. Veuillez redémarrer avec -reindex-chainstate. Cela reconstruira la base de données chainstate.</translation> + <translation type="unfinished">Un format non pris en charge de la base de données d’état de la chaîne a été trouvé. Redémarrez avec -reindex-chainstate. La base de données d’état de la chaîne sera reconstruite.</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> @@ -4237,7 +4256,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>%s is set very high! Fees this large could be paid on a single transaction.</source> - <translation type="unfinished">%s est très élevé ! Des frais aussi importants pourraient être payés sur une seule transaction.</translation> + <translation type="unfinished">%s est un montant très élevé. Des frais aussi élevés pourraient être payés en une seule transaction.</translation> </message> <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> @@ -4249,7 +4268,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> - <translation type="unfinished">Erreur de lecture de %s! Toutes les clés ont été lues correctement, mais les données de transaction ou les métadonnées d'adresse peuvent être manquantes ou incorrectes.</translation> + <translation type="unfinished">Erreur de lecture de %s. Toutes les clés ont été lues correctement, mais les données de la transaction ou les métadonnées de l’adresse sont peut-être manquantes ou incorrectes.</translation> </message> <message> <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> @@ -4265,7 +4284,7 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> - <translation type="unfinished">Échec du calcul des frais de majoration, car les UTXO non confirmés dépendent d'un énorme groupe de transactions non confirmées.</translation> + <translation type="unfinished">Échec de calcul de la majoration des frais, car les UTXO non confirmés dépendent d’un groupe énorme de transactions non confirmées.</translation> </message> <message> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> @@ -4273,31 +4292,31 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> - <translation type="unfinished">L'estimation des frais a échoué. Fallbackfee est désactivé. Attendez quelques blocs ou activez %s.</translation> + <translation type="unfinished">Échec d’estimation des frais. L’option de frais de repli « Fallbackfee » est désactivée. Attendez quelques blocs ou activez %s.</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 vers IPv4/IPv6</translation> + <translation type="unfinished">Options incompatibles : -dnsseed=1 a été indiqué explicitement, mais -onlynet interdit les connexions vers IPv4 et IPv6</translation> </message> <message> <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> - <translation type="unfinished">Montant non valide pour %s=<amount> : '%s' (doit être au moins égal au minrelay fee de %s pour éviter les transactions bloquées)</translation> + <translation type="unfinished">Le montant est invalide pour %s=<amount> : « %s » (doit être au moins égal aux frais minrelay de %s pour prévenir le blocage des transactions)</translation> </message> <message> <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> - <translation type="unfinished">Connexions sortantes limitées à CJDNS (-onlynet=cjdns) mais -cjdnsreachable n'est pas fourni</translation> + <translation type="unfinished">Les connexions sortantes sont limitées à CJDNS (-onlynet=cjdns), mais -cjdnsreachable n’est pas indiqué</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> + <translation type="unfinished">Les connexions sortantes sont limitées à Tor (-onlynet=onion), mais le mandataire pour accéder au 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 paramètres -proxy, -onion ou -listenonion n'est donné</translation> + <translation type="unfinished">Les connexions sortantes sont limitées à Tor (-onlynet=onion), mais le mandataire pour accéder au réseau Tor n’est pas indiqué : ni -proxy, ni -onion, ni -onion=0 n’est indiqué</translation> </message> <message> <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> - <translation type="unfinished">Connexions sortantes limitées à i2p (-onlynet=i2p) mais -i2psam n'est pas fourni</translation> + <translation type="unfinished">Les connexions sortantes sont limitées à i2p (-onlynet=i2p), mais -i2psam n’est pas indiqué</translation> </message> <message> <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> @@ -4305,15 +4324,15 @@ Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. </message> <message> <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">Le montant total des pièces présélectionnées ne couvre pas l'objectif de la transaction. Veuillez permettre à d'autres entrées d'être sélectionnées automatiquement ou inclure plus de pièces manuellement</translation> + <translation type="unfinished">Le montant total des pièces présélectionnées ne couvre pas l’objectif de la transaction. Permettez la sélection automatique d’autres entrées ou ajoutez d’autres pièces manuellement</translation> </message> <message> <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> - <translation type="unfinished">La transaction nécessite une destination d'une valeur non nulle, un ratio de frais non nul, ou une entrée présélectionnée.</translation> + <translation type="unfinished">Une destination d’une valeur non nulle, des taux de frais non nuls, ou une entrée présélectionnée sont nécessaires pour cette transaction</translation> </message> <message> <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> - <translation type="unfinished">La validation de la snapshot UTXO a échoué. Redémarrez pour reprendre le téléchargement normal du bloc initial, ou essayez de charger une autre snapshot.</translation> + <translation type="unfinished">Échec de validation de l’instantané UTXO. Redémarrez pour reprendre le téléchargement normal du bloc initial ou essayez de charger un instantané différent</translation> </message> <message> <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> @@ -4345,7 +4364,7 @@ Essayez d’utiliser la version la plus récente du logiciel. <source> Unable to cleanup failed migration</source> <translation type="unfinished"> -Impossible de corriger l'échec de la migration</translation> +Impossible de nettoyer la migration en échec</translation> </message> <message> <source> @@ -4435,7 +4454,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Error reading configuration file: %s</source> - <translation type="unfinished">Erreur de lecture du fichier de configuration : %s</translation> + <translation type="unfinished">Erreur de lecture du fichier de configuration : %s</translation> </message> <message> <source>Error reading from database, shutting down.</source> @@ -4451,7 +4470,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> - <translation type="unfinished">Erreur : Impossible d'extraire la destination du scriptpubkey généré</translation> + <translation type="unfinished">Erreur : impossible d’extraire la destination de la scriptpubkey générée</translation> </message> <message> <source>Error: Couldn't create cursor into database</source> @@ -4551,7 +4570,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Échec du démarrage des index, arrêt.</translation> + <translation type="unfinished">Échec du démarrage des index, arrêt</translation> </message> <message> <source>Failed to verify database</source> @@ -4587,7 +4606,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Insufficient dbcache for block verification</source> - <translation type="unfinished">Insuffisance de dbcache pour la vérification des blocs</translation> + <translation type="unfinished">dbcache est insuffisant pour la vérification des blocs</translation> </message> <message> <source>Insufficient funds</source> @@ -4611,11 +4630,11 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> - <translation type="unfinished">Montant non valide pour %s=<amount> : '%s' (doit être au moins %s)</translation> + <translation type="unfinished">Le montant est invalide pour %s=<amount> : « %s » (doit être au moins %s)</translation> </message> <message> <source>Invalid amount for %s=<amount>: '%s'</source> - <translation type="unfinished">Montant non valide pour %s=<amount> : '%s'</translation> + <translation type="unfinished">Le montant est invalide pour %s=<amount> : « %s »</translation> </message> <message> <source>Invalid amount for -%s=<amount>: '%s'</source> @@ -4627,15 +4646,15 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Invalid port specified in %s: '%s'</source> - <translation type="unfinished">Port non valide spécifié dans %s: '%s'</translation> + <translation type="unfinished">Un port non valide est indiqué dans %s : « %s »</translation> </message> <message> <source>Invalid pre-selected input %s</source> - <translation type="unfinished">Entrée présélectionnée non valide %s</translation> + <translation type="unfinished">L’entrée présélectionnée %s est invalide</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> + <translation type="unfinished">L’écoute des connexions entrantes a échoué (l’écoute a retourné l’erreur %s)</translation> </message> <message> <source>Loading P2P addresses…</source> @@ -4675,7 +4694,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Not found pre-selected input %s</source> - <translation type="unfinished">Entrée présélectionnée introuvable %s</translation> + <translation type="unfinished">L’entrée présélectionnée %s est introuvable</translation> </message> <message> <source>Not solvable pre-selected input %s</source> @@ -4747,7 +4766,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Specified data directory "%s" does not exist.</source> - <translation type="unfinished">Le répertoire de données spécifié "%s" n'existe pas.</translation> + <translation type="unfinished">Le répertoire de données indiqué « %s » n’existe pas</translation> </message> <message> <source>Starting network threads…</source> @@ -4807,11 +4826,11 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Transaction too large</source> - <translation type="unfinished">La transaction est trop grosse</translation> + <translation type="unfinished">La transaction est trop élevée</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' Mo</translation> + <translation type="unfinished">Impossible d’allouer de la mémoire pour -maxsigcachesize : « %s » Mio</translation> </message> <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> @@ -4827,7 +4846,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Unable to find UTXO for external input</source> - <translation type="unfinished">Impossible de trouver l'UTXO pour l'entrée externe</translation> + <translation type="unfinished">Impossible de trouver l’UTXO pour l’entrée externe</translation> </message> <message> <source>Unable to generate initial keys</source> @@ -4851,7 +4870,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Unable to unload the wallet before migrating</source> - <translation type="unfinished">Impossible de vider le portefeuille avant la migration</translation> + <translation type="unfinished">Impossible de décharger le porte-monnaie avant migration</translation> </message> <message> <source>Unknown -blockfilterindex value %s.</source> @@ -4875,7 +4894,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Unsupported global logging level %s=%s. Valid values: %s.</source> - <translation type="unfinished">Niveau de journalisation global non pris en charge %s=%s. Valeurs valides : %s.</translation> + <translation type="unfinished">Niveau de journalisation global non pris en charge %s=%s. Valeurs valides : %s.</translation> </message> <message> <source>Wallet file creation failed: %s</source> @@ -4883,7 +4902,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> - <translation type="unfinished">acceptstalefeeestimates n'est pas pris en charge sur la chaîne %s.</translation> + <translation type="unfinished">acceptstalefeeestimates n’est pas pris en charge sur la chaîne %s.</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> @@ -4911,7 +4930,7 @@ Impossible de restaurer la sauvegarde du porte-monnaie</translation> </message> <message> <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation type="unfinished">Le portefeuille doit être réécrit : redémarrer %s pour terminer</translation> + <translation type="unfinished">Le porte-monnaie devait être réécrit : redémarrer %s pour terminer l’opération.</translation> </message> <message> <source>Settings file could not be read</source> diff --git a/src/qt/locale/bitcoin_ga.ts b/src/qt/locale/bitcoin_ga.ts index 901748a146..f6410b5cd5 100644 --- a/src/qt/locale/bitcoin_ga.ts +++ b/src/qt/locale/bitcoin_ga.ts @@ -215,6 +215,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">AthraÃodh pasfhrása sparán go rathúil.</translation> </message> <message> + <source>Passphrase change failed</source> + <translation type="unfinished">Theip ar athrú pasfhocail</translation> + </message> + <message> + <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">Tá an seanphasfhrása a cuireadh isteach le haghaidh dÃchriptithe an sparán mÃcheart. Tá carachtar nialasach ann (ie - beart nialasach). Má socraÃodh an pasfhrása le leagan den bhogearra seo roimh 25.0, bain triail eile as gan ach na carachtair suas go dtà — ach gan a bheith san áireamh — an chéad charachtar null.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Rabhadh: Tá an eochair Glas Ceannlitreacha ar!</translation> </message> @@ -233,21 +241,55 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>BitcoinApplication</name> <message> + <source>Runaway exception</source> + <translation type="unfinished">Eisceacht runaway</translation> + </message> + <message> <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> <translation type="unfinished">Tharla earráid mharfach. Nà féidir le %1 leanúint ar aghaidh go sábháilte agus scoirfidh sé.</translation> </message> + <message> + <source>Internal error</source> + <translation type="unfinished">Earráid inmheánach</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">Ar mhaith leat socruithe a athshocrú go luachanna réamhshocraithe, nó deireadh a chur leis gan athruithe a dhéanamh?</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">Tharla earráid mharfach. Cinntigh go bhfuil an comhad socruithe inscrÃofa, nó bain triail as rith le -nosettings.</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Earráid: %1</translation> </message> <message> + <source>%1 didn't yet exit safely…</source> + <translation type="unfinished">NÃor scoir %1 go sábháilte fós…</translation> + </message> + <message> <source>unknown</source> <translation type="unfinished">neamhaithnid</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Leabaithe "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Cló réamhshocraithe an chórais "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Saincheaptha…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Suim</translation> </message> @@ -256,6 +298,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Iontráil seoladh Bitcoin (m.sh.%1)</translation> </message> <message> + <source>Unroutable</source> + <translation type="unfinished">Dothreoraithe</translation> + </message> + <message> + <source>Onion</source> + <comment>network name</comment> + <extracomment>Name of Tor network in peer info</extracomment> + <translation type="unfinished">Oinniún</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">Isteach</translation> @@ -266,6 +318,31 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Amach</translation> </message> <message> + <source>Full Relay</source> + <extracomment>Peer connection type that relays all network information.</extracomment> + <translation type="unfinished">SealaÃocht Iomlán</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">SealaÃocht Bloc</translation> + </message> + <message> + <source>Manual</source> + <extracomment>Peer connection type established manually through one of several methods.</extracomment> + <translation type="unfinished">Lámhleabhar</translation> + </message> + <message> + <source>Feeler</source> + <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> + <translation type="unfinished">Fearacht</translation> + </message> + <message> + <source>Address Fetch</source> + <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> + <translation type="unfinished">Seoladh Fetch</translation> + </message> + <message> <source>%1 d</source> <translation type="unfinished">%1 l</translation> </message> @@ -288,41 +365,41 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n soicind(Ã)</numerusform> + <numerusform>%n soicind(Ã)</numerusform> + <numerusform>%n soicind(Ã)</numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n nóiméad(a)</numerusform> + <numerusform>%n nóiméad(a)</numerusform> + <numerusform>%n nóiméad(a)</numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n uair(eanta)</numerusform> + <numerusform>%n uair(eanta)</numerusform> + <numerusform>%n uair(eanta)</numerusform> </translation> </message> <message numerus="yes"> <source>%n day(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n lá(/a)</numerusform> + <numerusform>%n lá(/a)</numerusform> + <numerusform>%n lá(/a)</numerusform> </translation> </message> <message numerus="yes"> <source>%n week(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n seachtain(/a)</numerusform> + <numerusform>%n seachtain(/a)</numerusform> + <numerusform>%n seachtain(/a)</numerusform> </translation> </message> <message> @@ -332,9 +409,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n bliain(/a)</numerusform> + <numerusform>%n bliain(/a)</numerusform> + <numerusform>%n bliain(/a)</numerusform> </translation> </message> </context> @@ -381,6 +458,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cruthaigh sparán nua</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished">&Ãoslaghdaigh</translation> + </message> + <message> <source>Wallet:</source> <translation type="unfinished">Sparán:</translation> </message> @@ -414,18 +495,62 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Glac</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Roghanna…</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Criptigh Sparán…</translation> + </message> + <message> <source>Encrypt the private keys that belong to your wallet</source> <translation type="unfinished">Criptigh na heochracha prÃobháideacha a bhaineann le do sparán</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Sparán Cúltaca…</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&Athraigh Pasfhocal…</translation> + </message> + <message> + <source>Sign &message…</source> + <translation type="unfinished">SÃnigh &teachtaireacht…</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> <translation type="unfinished">SÃnigh teachtaireachtaà le do sheoltaà Bitcoin chun a chruthú gur leat iad</translation> </message> <message> + <source>&Verify message…</source> + <translation type="unfinished">&FÃoraigh teachtaireacht…</translation> + </message> + <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> <translation type="unfinished">Teachtaireachtaà a fhÃorú lena chinntiú go raibh siad sÃnithe le seoltaà sainithe Bitcoin</translation> </message> <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Lódáil PSBT ón gcomhad…</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">Oscail &URI…</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">Dún Sparán…</translation> + </message> + <message> + <source>Create Wallet…</source> + <translation type="unfinished">Cruthaigh Sparán…</translation> + </message> + <message> + <source>Close All Wallets…</source> + <translation type="unfinished">Dún Gach Sparán…</translation> + </message> + <message> <source>&File</source> <translation type="unfinished">&Comhad</translation> </message> @@ -442,6 +567,26 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Barra uirlisà cluaisÃnÃ</translation> </message> <message> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Ceanntásca á Sioncronú (%1 %)…</translation> + </message> + <message> + <source>Synchronizing with network…</source> + <translation type="unfinished">Ag sioncronú le lÃonra…</translation> + </message> + <message> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Bloic á n-innéacsú ar an diosca…</translation> + </message> + <message> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Bloic ar diosca á bpróiseáil…</translation> + </message> + <message> + <source>Connecting to peers…</source> + <translation type="unfinished">Ag nascadh le piaraÃ…</translation> + </message> + <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished">Iarr ÃocaÃochtaà (gineann cóid QR agus bitcoin: URIs)</translation> </message> @@ -460,9 +605,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> </translation> </message> <message> @@ -470,6 +615,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 taobh thiar</translation> </message> <message> + <source>Catching up…</source> + <translation type="unfinished">Ag teacht suas…</translation> + </message> + <message> <source>Last received block was generated %1 ago.</source> <translation type="unfinished">Gineadh an bloc deireanach a fuarthas %1 ó shin.</translation> </message> @@ -498,6 +647,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Lódáil Idirbheart Bitcoin SÃnithe go Páirteach</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Luchtaigh PSBT ón &gearrthaisce…</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Lódáil Idirbheart Bitcoin SÃnithe go Páirteach ón gearrthaisce</translation> </message> @@ -534,10 +687,28 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Dún spará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">Athchóirigh Sparán…</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">Athchóirigh sparán ó chomhad cúltaca</translation> + </message> + <message> <source>Close all wallets</source> <translation type="unfinished">Dún gach sparán</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Imirce Sparán</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Imirce sparán</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished">Taispeáin an %1 teachtaireacht chabhrach chun liosta a fháil de roghanna Bitcoin lÃne na n-orduithe féideartha</translation> </message> @@ -558,6 +729,21 @@ 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 Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Sonraà Sparán</translation> + </message> + <message> + <source>Load Wallet Backup</source> + <extracomment>The title for Restore Wallet File Windows</extracomment> + <translation type="unfinished">Luchtaigh Cúltaca Sparán</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">Athchóirigh Sparán</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> @@ -578,16 +764,56 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>%1 client</source> <translation type="unfinished">%1 cliaint</translation> </message> + <message> + <source>&Hide</source> + <translation type="unfinished">&Folaigh</translation> + </message> + <message> + <source>S&how</source> + <translation type="unfinished">S&conas</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 nasc(Ã) gnÃomhacha le lÃonra Bitcoin.</numerusform> + <numerusform>%n nasc(Ã) gnÃomhacha le lÃonra Bitcoin.</numerusform> + <numerusform>%n nasc(Ã) gnÃomhacha le lÃonra 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">Cliceáil le haghaidh tuilleadh gnÃomhartha.</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">Taispeáin cluaisÃn PiaraÃ</translation> + </message> + <message> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished">DÃchumasaigh gnÃomhaÃocht lÃonra</translation> + </message> + <message> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished">Cumasaigh gnÃomhaÃocht lÃonra</translation> + </message> + <message> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Ceanntásca a réamhshioncronú (%1 %)…</translation> + </message> + <message> + <source>Error creating wallet</source> + <translation type="unfinished">Earráid agus sparán á chruthú</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">Nà féidir sparán nua a chruthú, tiomsaÃodh na bogearraà gan tacaÃocht sqlite (riachtanach le haghaidh sparán tuairisceora)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Earráid: %1</translation> </message> @@ -742,6 +968,30 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil suim</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">Cóipeáil idirbheart & ID agus innéacs aschuir</translation> + </message> + <message> + <source>L&ock unspent</source> + <translation type="unfinished">L&ocáil neamhchaite</translation> + </message> + <message> + <source>&Unlock unspent</source> + <translation type="unfinished">L&ocáil neamhchaite</translation> + </message> + <message> <source>Copy quantity</source> <translation type="unfinished">Cóipeáil méid</translation> </message> @@ -802,7 +1052,79 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>Create wallet warning</source> <translation type="unfinished">Rabhadh cruthú sparán</translation> </message> - </context> + <message> + <source>Can't list signers</source> + <translation type="unfinished">Nà féidir sÃnitheoirà a liostú</translation> + </message> + <message> + <source>Too many external signers found</source> + <translation type="unfinished">Fuarthas an iomarca sÃnitheoirà seachtracha</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">Luchtaigh Sparán</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">Sparán á lódáil…</translation> + </message> +</context> +<context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Imirce sparán</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">An bhfuil tú cinnte gur mian leat an sparán <i>%1 </i>?</translation> + </message> + <message> + <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> + <translation type="unfinished">Má dhéantar an sparán a aistriú, déanfar an sparán seo a thiontú go sparán tuairisceora amháin nó nÃos mó. Beidh gá le cúltaca sparán nua. +Má tá aon scripteanna faire amháin sa sparán seo, cruthófar sparán nua ina mbeidh na scripteanna faire amháin sin. +Má tá aon scripteanna intuaslagtha ach nach bhfuil faire orthu sa sparán seo, cruthófar sparán difriúil agus nua ina mbeidh na scripteanna sin. + +Cruthóidh an próiseas imirce cúltaca den sparán roimh imirce. Ainmneofar an comhad cúltaca seo <wallet name>-<timestamp>.legacy.bak agus is féidir é a fháil san eolaire don sparán seo. I gcás imirce mÃcheart, is féidir an cúltaca a chur ar ais leis an bhfeidhmiúlacht "Athchóirigh Sparán".</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Imirce Sparán</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">Sparán á Ascnamh <b>%1</b>…</translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">D'éirigh le haistriú an sparán '%1'.</translation> + </message> + <message> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">AistrÃodh scripteanna faire amháin go sparán nua darb ainm '%1'.</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">AistrÃodh scripteanna intuaslagtha ach nach bhfuiltear ag faire orthu go sparán nua darb ainm '%1'.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">Theip ar an imirce</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">D'éirigh leis an Imirce</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> <message> @@ -822,7 +1144,40 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Oscail Sparán</translation> </message> - </context> + <message> + <source>Opening Wallet <b>%1</b>…</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">Sparán Oscailte<b>%1</b>…</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">Athchóirigh Sparán</translation> + </message> + <message> + <source>Restoring Wallet <b>%1</b>…</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">Sparán á Athchóiriú<b>%1</b>…</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">Theip ar athchóiriú an sparán</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">Athchóirigh rabhadh sparán</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">Athchóirigh teachtaireacht sparán</translation> + </message> +</context> <context> <name>WalletController</name> <message> @@ -853,6 +1208,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cruthaigh Sparán</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Tá tú céim amháin ar shiúl ó chruthú do sparán nua!</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">Tabhair ainm le do thoil agus, más mian leat, cumasaigh aon ardroghanna</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Ainm Sparán</translation> </message> @@ -889,10 +1252,23 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Déan Sparán Glan</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">Bain úsáid as gléas sÃnithe seachtrach cosúil le sparán crua-earraÃ. Cumraigh an script sÃnitheora sheachtraigh i sainroghanna an sparán ar dtús.</translation> + </message> + <message> + <source>External signer</source> + <translation type="unfinished">SÃnitheoir seachtrach</translation> + </message> + <message> <source>Create</source> <translation type="unfinished">Cruthaigh</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">Tiomsaithe gan tacaÃocht sÃnithe seachtrach (riachtanach le haghaidh sÃniú seachtrach)</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -972,9 +1348,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n GB de spás ar fáil</numerusform> + <numerusform>%n GB de spás ar fáil</numerusform> + <numerusform>%n GB de spás ar fáil</numerusform> </translation> </message> <message numerus="yes"> @@ -994,6 +1370,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </translation> </message> <message> + <source>Choose data directory</source> + <translation type="unfinished">Roghnaigh eolaire sonraÃ</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> </message> @@ -1005,9 +1385,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</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>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> + <numerusform>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> + <numerusform>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> </translation> </message> <message> @@ -1039,6 +1419,10 @@ 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>Limit block chain storage to</source> + <translation type="unfinished">Teorainn a chur le blocshlabhra stórála go</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> @@ -1047,6 +1431,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Tá an sioncrónú tosaigh seo an-dhian, agus d’fhéadfadh sé fadhbanna crua-earraà a nochtadh le do rÃomhaire nach tugadh faoi deara roimhe seo. Gach uair a ritheann tú %1, leanfaidh sé ar aghaidh ag Ãoslódáil san áit ar fhág sé as.</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">Nuair a chliceálann tú OK, tosóidh %1 ag Ãosluchtú agus ag próiseáil slabhra iomlán %4 (%2 GB) ag tosú leis na hidirbhearta is luaithe i %3 nuair a seoladh %4 ar dtús.</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">Má roghnaigh tú stóráil blocshlabhra a theorannú (bearradh), fós caithfear na sonraà stairiúla a Ãoslódáil agus a phróiseáil, ach scriosfar iad ina dhiaidh sin chun d’úsáid diosca a choinneáil Ãseal.</translation> </message> @@ -1077,6 +1465,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>ShutdownWindow</name> <message> + <source>%1 is shutting down…</source> + <translation type="unfinished">Tá %1 ag múchadh…</translation> + </message> + <message> <source>Do not shut down the computer until this window disappears.</source> <translation type="unfinished">Ná múch an rÃomhaire go dtà go n-imÃonn an fhuinneog seo.</translation> </message> @@ -1100,6 +1492,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">LÃon na mbloic fágtha</translation> </message> <message> + <source>Unknown…</source> + <translation type="unfinished">Anaithnid…</translation> + </message> + <message> + <source>calculating…</source> + <translation type="unfinished">ag rÃomh…</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Am bloc deireanach</translation> </message> @@ -1123,7 +1523,15 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</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">Tá %1 ag sioncronú faoi láthair. Déanfaidh sé é a Ãoslódáil agus a fÃorú ar ceanntásca agus bloic ó phiaraà go dtà barr an blocshlabhra.</translation> </message> - </context> + <message> + <source>Unknown. Syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Anaithnid. Ceanntásca á Sioncronú (%1, %2 %)…</translation> + </message> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Anaithnid. Ceanntásca a Réamhshioncronú (%1, %2 %)…</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -1155,6 +1563,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Tosaigh %1 ar logáil isteach an chórais</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">LaghdaÃtear go mór an spás diosca a theastaÃonn chun idirbhearta a stóráil má dhéantar bearradh a chumasú. Tá gach bloc fós bailÃochtaithe go hiomlán. Chun an socrú seo a thabhairt ar ais nà mór an blockchain iomlán a athÃoslódáil.</translation> + </message> + <message> <source>Size of &database cache</source> <translation type="unfinished">Méid taisce &bunachar sonraÃ</translation> </message> @@ -1163,6 +1575,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">LÃon snáitheanna &fÃorú scripte</translation> </message> <message> + <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">Conair iomlán chuig script comhoiriúnach %1 (m.sh. C:\Downloads\hwi.exe nó /Users/you/Downloads/hwi.py). Tabhair aire: is féidir le malware do bhoinn a ghoid!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">Seoladh IP an seachfhreastalaà (m.sh. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -1175,6 +1591,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ãoslaghdaigh in ionad scoir an feidhmchlár nuair a bhÃonn an fhuinneog dúnta. Nuair a chumasófar an rogha seo, nà dhúnfar an feidhmchlár ach amháin tar éis Scoir a roghnú sa roghchlár.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Cló sa chluaisÃn Forbhreathnú:</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line:</source> + <translation type="unfinished">Tá na roghanna atá socraithe sa dialóg seo sáraithe ag an lÃne ordaithe:</translation> + </message> + <message> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished">Oscail an comhad cumraÃochta %1 ón eolaire oibre.</translation> </message> @@ -1203,14 +1627,44 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">TeastaÃonn an blocshlabhra iomlán a Ãoslódáil arÃs chun an socrú seo a fhilleadh.</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">Uasmhéid taisce bunachar sonraÃ. Is féidir le taisce nÃos mó cur le sioncrónú nÃos tapúla, agus ina dhiaidh sin nà bhÃonn an tairbhe chomh soiléir don chuid is mó de chásanna úsáide. Laghdófar úsáid chuimhne má laghdaÃtear méid an taisce. Roinntear cuimhne mempool neamhúsáidte don taisce seo.</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">Socraigh lÃon na snáitheanna fÃoraithe scripte. FreagraÃonn luachanna diúltacha do lÃon na gcroÃthe is mian leat a fhágáil saor sa chóras.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished">(0 = uath, <0 = fág an méid sin cóir saor)</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">Ligeann sé seo duit féin nó d’uirlis trÃú páirtà cumarsáid a dhéanamh leis an nód trà orduithe ordú-lÃne agus JSON-RPC.</translation> + </message> + <message> + <source>Enable R&PC server</source> + <extracomment>An Options window setting to enable the RPC server.</extracomment> + <translation type="unfinished">Cumasaigh freastalaà R&PC</translation> + </message> + <message> <source>W&allet</source> <translation type="unfinished">Sp&arán</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">Cibé an táille a dhealú ón méid a shocrú mar réamhshocrú nó nach bhfuil.</translation> + </message> + <message> + <source>Subtract &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">Dealaigh &táille ón méid de réir réamhshocraithe</translation> + </message> + <message> <source>Expert</source> <translation type="unfinished">Saineolach</translation> </message> @@ -1227,6 +1681,24 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Caith &sóinseáil neamhdheimhnithe</translation> </message> <message> + <source>Enable &PSBT controls</source> + <extracomment>An options window setting to enable PSBT controls.</extracomment> + <translation type="unfinished">Cumasaigh & rialuithe 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">Cibé ar cheart rialuithe PSBT a thaispeáint.</translation> + </message> + <message> + <source>External Signer (e.g. hardware wallet)</source> + <translation type="unfinished">SÃnitheoir Seachtrach (m.sh. sparán crua-earraÃ)</translation> + </message> + <message> + <source>&External signer script path</source> + <translation type="unfinished">&Conair scripte sÃnithe seachtraÃ</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">Oscail port cliant Bitcoin go huathoibrÃoch ar an ródaire. Nà oibrÃonn sé seo ach nuair a thacaÃonn do ródaire le UPnP agus nuair a chumasaÃtear é.</translation> </message> @@ -1235,6 +1707,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Mapáil port ag úsáid &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">Oscail calafort cliant Bitcoin go huathoibrÃoch ar an ródaire. Nà oibrÃonn sé seo ach amháin nuair a thacaÃonn do ródaire le NAT-PMP agus go bhfuil sé cumasaithe. D'fhéadfadh an port seachtrach a bheith randamach.</translation> + </message> + <message> + <source>Map port using NA&T-PMP</source> + <translation type="unfinished">Port léarscáil le NA&T-PMP</translation> + </message> + <message> <source>Accept connections from outside.</source> <translation type="unfinished">Glac le naisc ón taobh amuigh.</translation> </message> @@ -1267,6 +1747,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Fuinneog</translation> </message> <message> + <source>Show the icon in the system tray.</source> + <translation type="unfinished">Taispeáin an deilbhÃn i dtráidire an chórais.</translation> + </message> + <message> + <source>&Show tray icon</source> + <translation type="unfinished">&Taispeáin Ãocón an tráidire</translation> + </message> + <message> <source>Show only a tray icon after minimizing the window.</source> <translation type="unfinished">Ná taispeáin ach deilbhÃn tráidire t'éis an fhuinneog a Ãoslaghdú.</translation> </message> @@ -1299,6 +1787,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Roghnaigh an t-aonad foroinnte réamhshocraithe le taispeáint sa chomhéadan agus nuair a sheoltar boinn.</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">URLanna trÃú páirtà (m.sh. taiscéalaà bloc) atá le feiceáil sa chluaisÃn idirbheart mar mhÃreanna roghchláir comhthéacs. Cuirtear hais idirbhirt in ionad%s sa URL. Déantar URLanna iolracha a dheighilt le barra ingearach |.</translation> + </message> + <message> + <source>&Third-party transaction URLs</source> + <translation type="unfinished">URLanna idirbheart trÃú páirtÃ</translation> + </message> + <message> <source>Whether to show coin control features or not.</source> <translation type="unfinished">Gnéithe rialúchán bonn a thaispeáint nó nach.</translation> </message> @@ -1319,6 +1815,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Cealaigh</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">Tiomsaithe gan tacaÃocht sÃnithe seachtrach (riachtanach le haghaidh sÃniú seachtrach)</translation> + </message> + <message> <source>default</source> <translation type="unfinished">réamhshocrú</translation> </message> @@ -1337,6 +1838,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Atosú cliant ag teastáil chun athruithe a ghnÃomhachtú.</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">Déanfar cúltaca de na socruithe reatha ag "%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">Múchfar an cliant. Ar mhaith leat dul ar aghaidh?</translation> @@ -1352,6 +1858,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Úsáidtear an comhad cumraÃochta chun ardroghanna úsáideora a shonrú a sháraÃonn socruithe GUI. Freisin, sáróidh aon roghanna lÃne na n-orduithe an comhad cumraÃochta seo.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Leanúint ar aghaidh</translation> + </message> + <message> <source>Cancel</source> <translation type="unfinished">Cealaigh</translation> </message> @@ -1373,6 +1883,13 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </message> </context> <context> + <name>OptionsModel</name> + <message> + <source>Could not read setting "%1", %2.</source> + <translation type="unfinished">NÃorbh fhéidir socrú "%1", %2 a léamh.</translation> + </message> +</context> +<context> <name>OverviewPage</name> <message> <source>Form</source> @@ -1454,6 +1971,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>PSBTOperationsDialog</name> <message> + <source>PSBT Operations</source> + <translation type="unfinished">OibrÃochtaà PSBT</translation> + </message> + <message> <source>Sign Tx</source> <translation type="unfinished">SÃnigh Tx</translation> </message> @@ -1466,6 +1987,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil chuig Gearrthaisce</translation> </message> <message> + <source>Save…</source> + <translation type="unfinished">Sábháil…</translation> + </message> + <message> <source>Close</source> <translation type="unfinished">Dún</translation> </message> @@ -1478,6 +2003,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Theip ar sÃniú idirbheart: %1</translation> </message> <message> + <source>Cannot sign inputs while wallet is locked.</source> + <translation type="unfinished">Nà féidir ionchuir a shÃniú agus an sparán glasáilte.</translation> + </message> + <message> <source>Could not sign any more inputs.</source> <translation type="unfinished">NÃorbh fhéidir nÃos mó ionchuir a shÃniú.</translation> </message> @@ -1510,10 +2039,19 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Sábháil Sonraà Idirbheart</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">Idirbheart Páirt-SÃnithe (Dénártha)</translation> + </message> + <message> <source>PSBT saved to disk.</source> <translation type="unfinished">IBSP sábháilte ar dhiosca.</translation> </message> <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">Seoltar %1 go %2</translation> + </message> + <message> <source>own address</source> <translation type="unfinished">seoladh féin</translation> </message> @@ -1546,6 +2084,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Tá sÃni(ú/the) fós ag teastáil ón idirbheart.</translation> </message> <message> + <source>(But no wallet is loaded.)</source> + <translation type="unfinished">(Ach nÃl aon sparán luchtaithe.)</translation> + </message> + <message> <source>(But this wallet cannot sign transactions.)</source> <translation type="unfinished">(Ach nà féidir leis an sparán seo idirbhearta a shÃniú.)</translation> </message> @@ -1581,6 +2123,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Nà URI bailà é 'bitcoin://'. Úsáid 'bitcoin:' ina ionad.</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à féidir iarratas ÃocaÃochta a phróiseáil toisc nach dtacaÃtear le BIP70. +De bharr lochtanna slándála forleathan in BIP70, moltar go láidir neamhaird a dhéanamh d’aon treoracha ceannaithe chun sparán a athrú. +Má tá an earráid seo á fáil agat ba cheart duit iarraidh ar an dÃoltóir URI atá comhoiriúnach le BIP21 a sholáthar.</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">Nà féidir URI a pharsáil! Is féidir le seoladh neamhbhailà Bitcoin nó paraiméadair URI drochfhoirmithe a bheith mar an chúis.</translation> </message> @@ -1597,6 +2147,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">GnÃomhaire Úsáideora</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">PiaraÃ</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">Aois</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">Treo</translation> @@ -1640,6 +2200,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>QRImageWidget</name> <message> + <source>&Save Image…</source> + <translation type="unfinished">&Sábháil Ãomhá…</translation> + </message> + <message> <source>&Copy Image</source> <translation type="unfinished">&Cóipeáil Ãomhá</translation> </message> @@ -1659,7 +2223,12 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>Save QR Code</source> <translation type="unfinished">Sabháil cód 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">Ãomhá PNG</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> @@ -1759,10 +2328,34 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Roghnaigh piara chun faisnéis mhionsonraithe a fheiceáil.</translation> </message> <message> + <source>The transport layer version: %1</source> + <translation type="unfinished">Leagan na sraithe iompair: %1</translation> + </message> + <message> + <source>Transport</source> + <translation type="unfinished">Iompar</translation> + </message> + <message> + <source>The BIP324 session ID string in hex, if any.</source> + <translation type="unfinished">Teaghrán ID an tseisiúin BIP324 i heicsidheachúlach, más ann dó.</translation> + </message> + <message> + <source>Session ID</source> + <translation type="unfinished">Aitheantas an tseisiúin</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Leagan</translation> </message> <message> + <source>Whether we relay transactions to this peer.</source> + <translation type="unfinished">Cibé an ndéanaimid idirbhearta a athsheoladh chuig an bpiaraà seo.</translation> + </message> + <message> + <source>Transaction Relay</source> + <translation type="unfinished">Leaschraolacháin Idirbheart</translation> + </message> + <message> <source>Starting Block</source> <translation type="unfinished">Bloc Tosaigh</translation> </message> @@ -1775,6 +2368,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Bloic Sioncronaithe</translation> </message> <message> + <source>Last Transaction</source> + <translation type="unfinished">Idirbheart Deiridh</translation> + </message> + <message> <source>The mapped Autonomous System used for diversifying peer selection.</source> <translation type="unfinished">An Córas Uathrialach mapáilte a úsáidtear chun roghnú piaraà a éagsúlú.</translation> </message> @@ -1783,6 +2380,36 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">CU Mapáilte</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">Cibé an gcuirfimid seoltaà chuig an bpiaraà seo.</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">SealaÃocht Seoladh</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">LÃon iomlán na seoltaà a fuarthas ón bpiaraà seo a próiseáladh (nà áirÃtear seoltaà a laghdaÃodh mar gheall ar theorannú rátaÃ).</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">LÃon iomlán na seoltaà a fuarthas ón bpiaraà seo a thit (nár próiseáladh) mar gheall ar theorannú rátaÃ.</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">Seoltaà Próiseáilte</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">Seoltaà Ráta-Teoranta</translation> + </message> + <message> <source>User Agent</source> <translation type="unfinished">GnÃomhaire Úsáideora</translation> </message> @@ -1811,14 +2438,47 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ceadanna</translation> </message> <message> + <source>The direction and type of peer connection: %1</source> + <translation type="unfinished">Treo agus cineál an naisc phiara: %1</translation> + </message> + <message> + <source>Direction/Type</source> + <translation type="unfinished">Treo/Cineál</translation> + </message> + <message> + <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> + <translation type="unfinished">An prótacal lÃonra a bhfuil an piara seo ceangailte trÃ: IPv4, IPv6, Oinniún, I2P, nó CJDNS.</translation> + </message> + <message> <source>Services</source> <translation type="unfinished">SeirbhÃsÃ</translation> </message> <message> + <source>High bandwidth BIP152 compact block relay: %1</source> + <translation type="unfinished">Bandaleithead ard BIP152 sealaÃochta bloc dhlúth: %1</translation> + </message> + <message> + <source>High Bandwidth</source> + <translation type="unfinished">Bandaleithid Ard</translation> + </message> + <message> <source>Connection Time</source> <translation type="unfinished">Am Ceangail</translation> </message> <message> + <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> + <translation type="unfinished">Tá achar ama caite ó fuarthas bloc úrscéil a rinne na seiceálacha bailÃochta tosaigh ón gcomhghleacaà seo.</translation> + </message> + <message> + <source>Last Block</source> + <translation type="unfinished">Bloc Deireanach</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">Chuaigh an t-am caite ó fuarthas idirbheart úrnua a glacadh isteach inár mempool ón bpiaraà seo.</translation> + </message> + <message> <source>Last Send</source> <translation type="unfinished">Seol Deireanach</translation> </message> @@ -1883,6 +2543,63 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Amach:</translation> </message> <message> + <source>Inbound: initiated by peer</source> + <extracomment>Explanatory text for an inbound peer connection.</extracomment> + <translation type="unfinished">Isteach: arna thionscnamh ag piaraÃ</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">SealaÃocht Iomlán Amach: réamhshocraithe</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">Leaschraolacháin Bloc Amach: nà athsheoltar idirbhearta ná seoltaÃ</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 Amach: gearrthéarmach, le haghaidh seoltaà tástála</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">Faigh Seoladh Amach: gearrthéarmach, chun seoltaà a lorg</translation> + </message> + <message> + <source>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">bhrath: d’fhéadfadh v1 nó v2 a bheith i gcomhghleacaÃ</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: prótacal iompair gnáththéacs gan chriptiú</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: BIP324 prótacal iompair criptithe</translation> + </message> + <message> + <source>we selected the peer for high bandwidth relay</source> + <translation type="unfinished">roghnaigh muid an piaraà le haghaidh sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>the peer selected us for high bandwidth relay</source> + <translation type="unfinished">roghnaigh an piaraà sinn le haghaidh sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>no high bandwidth relay selected</source> + <translation type="unfinished">nÃor roghnaÃodh aon sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>&Copy address</source> + <extracomment>Context menu action to copy the address of a peer.</extracomment> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> <source>&Disconnect</source> <translation type="unfinished">&Scaoil</translation> </message> @@ -1891,6 +2608,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">1 &uair</translation> </message> <message> + <source>1 d&ay</source> + <translation type="unfinished">1 l&á</translation> + </message> + <message> <source>1 &week</source> <translation type="unfinished">1 &seachtain</translation> </message> @@ -1899,6 +2620,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">1 &bhliain</translation> </message> <message> + <source>&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">&Cóipeáil IP/Netmask</translation> + </message> + <message> <source>&Unban</source> <translation type="unfinished">&DÃchosc</translation> </message> @@ -1911,10 +2637,40 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ag rith ordú gan aon sparán</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Fuinneog nód - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Ag rith ordú ag úsáid sparán "%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">Fáilte go consól RPC %1. +Úsáid saigheada suas agus sÃos chun an stair a nascleanúint, agus %2 chun an scáileán a ghlanadh. +Úsáid %3 agus %4 chun an clómhéid a mhéadú nó a laghdú. +ClóscrÃobh %5 le haghaidh forbhreathnú ar na horduithe atá ar fáil. +Chun tuilleadh eolais a fháil faoin gconsól seo a úsáid, clóscrÃobh %6. + +%7 RABHADH: Bhà scamadóirà gnÃomhach, ag rá le húsáideoirà orduithe a chlóscrÃobh anseo, ag goid a n-inneachar sparán. Ná húsáid an consól seo gan iarmhairtà ordaithe a thuiscint go hiomlán.%8</translation> + </message> + <message> + <source>Executing…</source> + <extracomment>A console message indicating an entered command is currently being executed.</extracomment> + <translation type="unfinished">Ag rith…</translation> + </message> + <message> + <source>(peer: %1)</source> + <translation type="unfinished">(piara: %1)</translation> + </message> + <message> <source>via %1</source> <translation type="unfinished">trà %1</translation> </message> @@ -1939,6 +2695,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cosc do</translation> </message> <message> + <source>Never</source> + <translation type="unfinished">Riamh</translation> + </message> + <message> <source>Unknown</source> <translation type="unfinished">Anaithnid</translation> </message> @@ -2018,6 +2778,46 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil &URI</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &message</source> + <translation type="unfinished">Cóipeáil & teachtaireacht</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Bonn58 (Oidhreacht)</translation> + </message> + <message> + <source>Not recommended due to higher fees and less protection against typos.</source> + <translation type="unfinished">Nà mholtar mar gheall ar tháillà nÃos airde agus cosaint nÃos lú i gcoinne typos.</translation> + </message> + <message> + <source>Base58 (P2SH-SegWit)</source> + <translation type="unfinished">Base58 (P2SH- SegWit)</translation> + </message> + <message> + <source>Generates an address compatible with older wallets.</source> + <translation type="unfinished">Gineann seoladh atá comhoiriúnach le sparán nÃos sine.</translation> + </message> + <message> + <source>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> + <translation type="unfinished">Gineann sé seoladh segwit dúchais (BIP-173). Nà thacaÃonn roinnt sean-sparán leis.</translation> + </message> + <message> + <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> + <translation type="unfinished">Is uasghrádú é Bech32m (BIP-350) go Bech32, tá tacaÃocht sparán fós teoranta.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation type="unfinished">NÃorbh fhéidir sparán a dhÃghlasáil.</translation> </message> @@ -2029,6 +2829,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>ReceiveRequestDialog</name> <message> + <source>Request payment to …</source> + <translation type="unfinished">Iarr ÃocaÃocht chuig…</translation> + </message> + <message> <source>Address:</source> <translation type="unfinished">Seoladh:</translation> </message> @@ -2057,6 +2861,18 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil &Seoladh</translation> </message> <message> + <source>&Verify</source> + <translation type="unfinished">&FÃoraigh</translation> + </message> + <message> + <source>Verify this address on e.g. a hardware wallet screen</source> + <translation type="unfinished">FÃoraigh an seoladh seo ar e.g. scáileán sparán crua-earraÃ</translation> + </message> + <message> + <source>&Save Image…</source> + <translation type="unfinished">&Sábháil Ãomhá…</translation> + </message> + <message> <source>Payment information</source> <translation type="unfinished">Faisnéis ÃocaÃochta</translation> </message> @@ -2187,10 +3003,26 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Glan gach réimse den fhoirm.</translation> </message> <message> + <source>Inputs…</source> + <translation type="unfinished">Ionchuir…</translation> + </message> + <message> + <source>Choose…</source> + <translation type="unfinished">Roghnaigh…</translation> + </message> + <message> <source>Hide transaction fee settings</source> <translation type="unfinished">Folaigh socruithe táillà idirbhirt</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">Sonraigh táille shaincheaptha in aghaidh an kB (1,000 beart) de mhéid fÃorúil an idirbhirt. + +Nóta: Ós rud é go rÃomhtar an táille ar bhonn in aghaidh an bheart, nà thabharfadh ráta táille "100 satoshis in aghaidh an kvB" le haghaidh méid idirbhirt 500 beart fÃorúil (leath de 1 kvB) táille ach 50 satoshis ar deireadh thiar.</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">Nuair a bhÃonn méid idirbhirt nÃos lú ná spás sna bloic, féadfaidh mianadóirà chomh maith le nóid athsheachadadh táille Ãosta a fhorfheidhmiú. Tá sé sách maith an táille Ãosta seo a Ãoc, ach bÃodh a fhios agat go bhféadfadh idirbheart nach ndeimhnÃtear riamh a bheith mar thoradh air seo a nuair a bhÃonn nÃos mó éilimh ar idirbhearta bitcoin ná mar is féidir leis an lÃonra a phróiseáil.</translation> </message> @@ -2199,6 +3031,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">D’fhéadfadh idirbheart nach ndeimhnÃtear riamh a bheith mar thoradh ar tháille ró-Ãseal (léigh an leid uirlise)</translation> </message> <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> + <translation type="unfinished">(NÃor cuireadh tús leis an táille chliste go fóill. Tógann sé seo cúpla bloc de ghnáth...)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation type="unfinished">Sprioc am dearbhaithe:</translation> </message> @@ -2255,6 +3091,20 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 (%2 bloic)</translation> </message> <message> + <source>Sign on device</source> + <extracomment>"device" usually means a hardware wallet.</extracomment> + <translation type="unfinished">SÃnigh ar an ngléas</translation> + </message> + <message> + <source>Connect your hardware wallet first.</source> + <translation type="unfinished">Ceangail do sparán crua-earraà ar dtús.</translation> + </message> + <message> + <source>Set external signer script path in Options -> Wallet</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">Socraigh cosán script sÃnitheora seachtrach i Roghanna -> Sparán</translation> + </message> + <message> <source>Cr&eate Unsigned</source> <translation type="unfinished">Cruthaigh Gan SÃn</translation> </message> @@ -2271,15 +3121,42 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 go %2</translation> </message> <message> + <source>To review recipient list click "Show Details…"</source> + <translation type="unfinished">Chun liosta na bhfaighteoirà a athbhreithniú cliceáil "Taispeáin SonraÃ…"</translation> + </message> + <message> + <source>Sign failed</source> + <translation type="unfinished">Theip ar an sÃniú</translation> + </message> + <message> + <source>External signer not found</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">NÃor aimsÃodh sÃnitheoir seachtrach</translation> + </message> + <message> + <source>External signer failure</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">Teip sÃnitheora sheachtraigh</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">Sábháil Sonraà Idirbheart</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">Idirbheart Páirt-SÃnithe (Dénártha)</translation> + </message> + <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> <translation type="unfinished">IBSP sábháilte</translation> </message> <message> + <source>External balance:</source> + <translation type="unfinished">Iarmhéid seachtrach:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">nó</translation> </message> @@ -2293,6 +3170,15 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Le do thoil, déan athbhreithniú ar do thogra idirbhirt. Tabharfaidh sé seo Idirbheart Bitcoin SÃnithe go Páirteach (IBSP) ar féidir leat a shábháil nó a chóipeáil agus a shÃniú ansin le m.sh. sparán as lÃne %1, nó sparán crua-earraà atá comhoiriúnach le IBSP.</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 ó sparán '%2'</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">Ar mhaith leat an t-idirbheart seo a chruthú?</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">Le do thoil, déan athbhreithniú ar d’idirbheart.</translation> @@ -2310,6 +3196,20 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Iomlán</translation> </message> <message> + <source>Unsigned Transaction</source> + <comment>PSBT copied</comment> + <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> + <translation type="unfinished">Idirbheart Gan SÃnithe</translation> + </message> + <message> + <source>The PSBT has been copied to the clipboard. You can also save it.</source> + <translation type="unfinished">Tá an PSBT cóipeáilte chuig an ngearrthaisce. Is féidir leat é a shábháil freisin.</translation> + </message> + <message> + <source>PSBT saved to disk</source> + <translation type="unfinished">PSBT sábháilte ar diosca</translation> + </message> + <message> <source>Confirm send coins</source> <translation type="unfinished">Deimhnigh seol boinn</translation> </message> @@ -2348,9 +3248,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> </translation> </message> <message> @@ -2588,6 +3488,17 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </message> </context> <context> + <name>SplashScreen</name> + <message> + <source>(press q to shutdown and continue later)</source> + <translation type="unfinished">(brúigh q chun múchadh agus lean ar aghaidh ar ball)</translation> + </message> + <message> + <source>press q to shutdown</source> + <translation type="unfinished">brúigh q chun múchadh</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -2595,6 +3506,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">faoi choimhlint le idirbheart le %1 dearbhuithe</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/neamhdhearbhaithe, i linn cuimhne</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/neamhdhearbhaithe, nà sa 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> @@ -2656,9 +3577,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> </translation> </message> <message> @@ -2710,6 +3631,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Innéacs aschuir</translation> </message> <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (NÃor fÃoraÃodh an teastas)</translation> + </message> + <message> <source>Merchant</source> <translation type="unfinished">CeannaÃ</translation> </message> @@ -2895,6 +3820,55 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ãosmhéid</translation> </message> <message> + <source>Range…</source> + <translation type="unfinished">Raon…</translation> + </message> + <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Copy transaction &ID</source> + <translation type="unfinished">Cóipeáil idirbheart &ID</translation> + </message> + <message> + <source>Copy &raw transaction</source> + <translation type="unfinished">Cóipeáil &amh-idirbheart</translation> + </message> + <message> + <source>Copy full transaction &details</source> + <translation type="unfinished">Cóipeáil idirbheart agus sonraà iomlána</translation> + </message> + <message> + <source>&Show transaction details</source> + <translation type="unfinished">&Taispeáin sonraà idirbhirt</translation> + </message> + <message> + <source>Increase transaction &fee</source> + <translation type="unfinished">Méadaigh idirbheart & táille</translation> + </message> + <message> + <source>A&bandon transaction</source> + <translation type="unfinished">Idirbheart&tréigean</translation> + </message> + <message> + <source>&Edit address label</source> + <translation type="unfinished">&Cuir lipéad seolta in eagar</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">Taispeáin i %1</translation> + </message> + <message> <source>Export Transaction History</source> <translation type="unfinished">Easpórtáil Stair Idirbheart</translation> </message> @@ -3023,6 +3997,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Táille nua:</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">Rabhadh: D’fhéadfadh sé seo an táille bhreise a Ãoc trà aschuir athraithe a laghdú nó trà ionchuir a chur leis, nuair is gá. Féadfaidh sé aschur athraithe nua a chur leis mura bhfuil ceann ann cheana. D'fhéadfadh na hathruithe seo prÃobháideacht a sceitheadh.</translation> + </message> + <message> <source>Confirm fee bump</source> <translation type="unfinished">Dearbhaigh preab táille</translation> </message> @@ -3035,6 +4013,11 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">IBSP cóipeáilte</translation> </message> <message> + <source>Copied to clipboard</source> + <comment>Fee-bump PSBT saved</comment> + <translation type="unfinished">Cóipeáladh chuig an ngearrthaisce</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Nà féidir sÃniú idirbheart.</translation> </message> @@ -3043,6 +4026,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃorbh fhéidir feidhmiú idirbheart</translation> </message> <message> + <source>Can't display address</source> + <translation type="unfinished">Nà féidir an seoladh a thaispeáint</translation> + </message> + <message> <source>default wallet</source> <translation type="unfinished">sparán réamhshocraithe</translation> </message> @@ -3062,6 +4049,11 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Sparán Chúltaca</translation> </message> <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Sonraà Sparán</translation> + </message> + <message> <source>Backup Failed</source> <translation type="unfinished">Theip ar cúltacú</translation> </message> @@ -3093,18 +4085,86 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Tá %s truaillithe. Triail an uirlis sparán bitcoin-wallet a úsáid chun tharrtháil nó chun cúltaca a athbhunú.</translation> </message> <message> + <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> + <translation type="unfinished">Theip ar %s an staid snapshot -assumeutxo a bhailÃochtú. LéirÃonn sé seo fadhb crua-earraÃ, nó fabht sna bogearraÃ, nó droch-mhodhnú bogearraà a cheadaigh pictiúr neamhbhailà a luchtú. Mar thoradh air seo, stopfar an nód agus stopfaidh sé de úsáid a bhaint as staid ar bith a tógadh ar an seat, ag athshocrú airde an tslabhra ó%dgo%d. Ar an gcéad atosú eile, athchromfar ar an nód ag sioncronú ó %d gan úsáid a bhaint as sonraà seat. Tuairiscigh an teagmhas seo do %s lena n-áirÃtear conas a fuair tú an pictiúr. Fágfar an slabhrashlabhra neamhbhailà ar an diosca ar eagla go mbeadh sé ina chuidiú leis an tsaincheist ba chúis leis an earráid seo a dhiagnóisiú.</translation> + </message> + <message> + <source>%s request to listen on port %u. This port is considered "bad" 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">Iarraidh %s éisteacht ar phort %u. Meastar go bhfuil an port seo "olc" agus dá bhrà sin nà dócha go nascfaidh piaraà ar bith leis. Féach doc/p2p-bad-ports.md le haghaidh sonraà agus liosta iomlán.</translation> + </message> + <message> + <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> + <translation type="unfinished">Nà féidir an sparán a Ãosghrádú ó leagan %igo leagan%i. Leagan sparán gan athrú.</translation> + </message> + <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation type="unfinished">Nà féidir glas a fháil ar eolaire sonraà %s. Is dócha go bhfuil %s ag rith cheana.</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">Nà féidir sparán scoilte neamh-HD a uasghrádú ó leagan%igo leagan%i gan uasghrádú chun tacú le heochrach réamh-scoilte. Úsáid leagan %i nó nÃl aon leagan sonraithe.</translation> + </message> + <message> + <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">Nà féidir spás diosca le haghaidh %sa chur san áireamh sna blocchomhaid. Stórálfar thart ar %u GB de shonraà san eolaire seo.</translation> + </message> + <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished">Dáilte faoin gceadúnas bogearraà MIT, féach na comhad atá in éindà %s nó %s</translation> </message> <message> + <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">Earráid agus an sparán á lódáil. ÉilÃonn Sparán go n-Ãoslódálfar bloic, agus nà thacaÃonn bogearraà faoi láthair le sparán a luchtú agus bloic á n-Ãoslódáil as ord nuair a úsáidtear snapshots assumeutxo. Ba cheart go mbeadh Sparán in ann luchtú go rathúil nuair a shroicheann sioncronú nód an airde %s</translation> + </message> + <message> + <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> + <translation type="unfinished">Earráid agus %s á léamh! Seans go bhfuil sonraà idirbhirt in easnamh nó mÃcheart. Sparán athscanadh.</translation> + </message> + <message> + <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <translation type="unfinished">Earráid agus%s á léamh! Seans go bhfuil sonraà idirbhirt in easnamh nó mÃcheart. Sparán athscanadh.</translation> + </message> + <message> + <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> + <translation type="unfinished">Earráid: Tá taifead aitheantóra Dumpfile mÃcheart. Fuair ​​​​tú "%s", bhÃothas ag súil le "%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">Earráid: Nà thacaÃtear leis an leagan Dumpfile. Nà thacaÃonn an leagan seo de bitcoin-sparán ach le leagan 1 dumpfiles. Fuair ​​​​tú dumpfile le leagan %s</translation> + </message> + <message> + <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> + <translation type="unfinished">Earráid: Nà thacaÃonn sparán oidhreachta ach na cineálacha seoltaà "oidhreacht", "p2sh-segwit", agus "bech32"</translation> + </message> + <message> + <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> + <translation type="unfinished">Earráid: Nà féidir tuairisceoirà a tháirgeadh don sparán oidhreachta seo. Bà cinnte pasfhrása an sparán a sholáthar má tá sé criptithe.</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">Tá comhad %s ann cheana. Má tá tú cinnte gurb é seo a theastaÃonn uait, bog é as an mbealach ar dtú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 neamhbhailà nó truaillithe (%s). Má chreideann tú gur fabht é seo, cuir in iúl do %s é le do thoil. Mar shruth oibre, is féidir leat an comhad (%s) a bhogadh as an mbealach (athainmnigh, bog nó scrios) chun ceann nua a chruthú ar an gcéad thús eile.</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">Tá nÃos mó ná seoladh ceangail oinniún amháin curtha ar fáil. Ag baint úsáide as %s don tseirbhÃs Tor oinniún a cruthaÃodh go huathoibrÃoch.</translation> </message> <message> + <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh aon chomhad dumpála. Chun createfromdump a úsáid, nà mór -dumpfile=<filename> a sholáthar.</translation> + </message> + <message> + <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh aon chomhad dumpála. Chun Dumpáil a úsáid, nà mór -dumpfile=<filename> a sholáthar.</translation> + </message> + <message> + <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh formáid comhaid sparán. Chun createfromdump a úsáid, nà mór -format=<format> a sholáthar.</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">Le do thoil seiceáil go bhfuil dáta agus am do rÃomhaire ceart! Má tá do chlog mÃcheart, nà oibreoidh %s i gceart.</translation> </message> @@ -3117,10 +4177,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Bearradh cumraithe faoi bhun an Ãosmhéid %d MiB. Úsáid uimhir nÃos airde le do thoil.</translation> </message> <message> + <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> + <translation type="unfinished">NÃl an modh prúnaà ag luà le -reindex-chainstate. Úsáid lán-reindex ina ionad sin.</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">Bearradh: téann sioncrónú deireanach an sparán thar sonraà bearrtha. Nà mór duit -reindex (déan an blockchain iomlán a Ãoslódáil arÃs i gcás nód bearrtha)</translation> </message> <message> + <source>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.</source> + <translation type="unfinished">Theip ar athainmniú '%s' -> '%s'. Ba cheart duit é seo a réiteach trÃd an gcomhadlann achomair neamhbhailà %s a bhogadh nó a scriosadh de láimh, nó beidh an earráid chéanna agat arÃs ar an gcéad tosaithe eile.</translation> + </message> + <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> <translation type="unfinished">SQLiteDatabase: Leagan scéime sparán sqlite anaithnid %d. Nà thacaÃtear ach le leagan %d</translation> </message> @@ -3161,6 +4229,30 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir bloic a aithrise. Beidh ort an bunachar sonraà a atógáil ag úsáid -reindex-chainstate.</translation> </message> <message> + <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> + <translation type="unfinished">Cuireadh formáid comhaid sparán anaithnid "%s" ar fáil. Tabhair ceann de "bdb" nó "sqlite".</translation> + </message> + <message> + <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> + <translation type="unfinished">Leibhéal logála catagóir ar leith nach dtacaÃtear leis%11$s=%2$s. BhÃothas ag súil le %1$s=1:2. Catagóirà bailÃ: %3$s. Leibhéil loga bailÃ: %4$s.</translation> + </message> + <message> + <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> + <translation type="unfinished">AimsÃodh formáid bhunachar sonraà chainstáit nach dtacaÃtear léi. Atosaigh le -reindex-chainstate. Déanfaidh sé seo an bunachar sonraà slabhrach a atógáil.</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">Sparán cruthaithe go rathúil. Tá an cineál sparán oidhreachta á dhÃmheas agus bainfear an tacaÃocht chun sparán oidhreachta a chruthú agus a oscailt amach anseo.</translation> + </message> + <message> + <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> + <translation type="unfinished">D'éirigh leis an sparán a lódáil. Tá an cineál sparán oidhreachta á dhÃmheas agus bainfear an tacaÃocht chun sparán oidhreachta a chruthú agus a oscailt amach anseo. Is féidir sparán oidhreachta a aistriú chuig sparán tuairisceora le sparán imirceach.</translation> + </message> + <message> + <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <translation type="unfinished">Rabhadh: Nà mheaitseálann formáid sparán Dumpfile "%s" an fhormáid ordaithe sonraithe "%s".</translation> + </message> + <message> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation type="unfinished">Rabhadh: Eochracha prÃobháideacha braite i sparán {%s} le heochracha prÃobháideacha dÃchumasaithe</translation> </message> @@ -3169,6 +4261,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Rabhadh: Is cosúil nach n-aontaÃmid go hiomlán lenár piaraÃ! B’fhéidir go mbeidh ort uasghrádú a dhéanamh, nó b’fhéidir go mbeidh ar nóid eile uasghrádú.</translation> </message> <message> + <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> + <translation type="unfinished">TeastaÃonn bailÃochtú sonraà finné maidir le bloic tar éis airde %d. Atosaigh le -reindex le do thoil.</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">Nà mór duit an bunachar sonraà a atógáil ag baint úsáide as -reindex chun dul ar ais go mód neamhbhearrtha. Déanfaidh sé seo an blockchain iomlán a athlódáil</translation> </message> @@ -3189,6 +4285,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir réiteach seoladh -%s: '%s'</translation> </message> <message> + <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> + <translation type="unfinished">Nà féidir -forcednsseed a shocrú go fÃor agus -dnsseed á shocrú go bréagach.</translation> + </message> + <message> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> <translation type="unfinished">Nà féidir -peerblockfilters a shocrú gan -blockfilterindex.</translation> </message> @@ -3197,6 +4297,126 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir scrÃobh chuig eolaire sonraà '%s'; seiceáil ceadanna.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">Tá%s socraithe an-ard! D’fhéadfaà táillà chomh mór seo a Ãoc ar idirbheart amháin.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> + <translation type="unfinished">Nà féidir naisc ar leith a sholáthar agus tá addrman chun naisc amach a aimsiú ag an am céanna.</translation> + </message> + <message> + <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source> + <translation type="unfinished">Earráid agus %s á lódáil: sparán an tsÃnitheora sheachtraigh á luchtú gan tacaÃocht sÃnitheoir seachtrach a chur le chéile</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> + <translation type="unfinished">Earráid agus %s á léamh! Léann na heochracha go léir i gceart, ach seans go bhfuil sonraà idirbhirt nó meiteashonraà seolta in easnamh nó mÃcheart.</translation> + </message> + <message> + <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Earráid: Nà féidir sonraà an leabhair seoltaà sa sparán a shainaithint mar go mbaineann siad le sparán aistrithe</translation> + </message> + <message> + <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> + <translation type="unfinished">Earráid: Tuairisceoirà dúblacha a cruthaÃodh le linn imirce. Seans go bhfuil do sparán truaillithe.</translation> + </message> + <message> + <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Earráid: Nà féidir idirbheart %s sa sparán a aithint gur le sparán aistrithe é</translation> + </message> + <message> + <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> + <translation type="unfinished">Theip ar tháillà tuairte a rÃomh, toisc go mbraitheann UTXOanna neamhdhearbhaithe ar bhraisle ollmhór idirbheart neamhdheimhnithe.</translation> + </message> + <message> + <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> + <translation type="unfinished">Theip ar an gcomhad peers.dat neamhbhailà a athainmniú. Bog nó scrios é agus bain triail eile as.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">Theip ar mheastachán na dtáillÃ. Tá fallbackfee dÃchumasaithe. Fan cúpla bloc nó cumasaigh %s.</translation> + </message> + <message> + <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> + <translation type="unfinished">Roghanna neamh-chomhoiriúnacha: -dnsseed=1 sonraÃodh go sainráite, ach cuireann -onlynet cosc ​​ar naisc le IPv4/IPv6</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=1: '%s' (nà mór an táille sealaÃochta nóiméad de %s a bheith ann ar a laghad chun idirbhearta bhfostú a chosc)</translation> + </message> + <message> + <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> + <translation type="unfinished">Naisc amach teoranta do CJDNS (-onlynet=cjdns) ach nà chuirtear -cjdnsreachable ar fáil</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">Tá naisc amach teoranta do Tor (-onlynet=onion) ach tá cosc ​​sainráite ar an seachfhreastalaà chun lÃonra Tor a bhaint amach: -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">Naisc amach teoranta do Tor (-onlynet=onion) ach nà thugtar an seachfhreastalaà chun lÃonra Tor a bhaint amach: nà thugtar aon seachfhreastalaÃ, -oinniún nó -listenonion</translation> + </message> + <message> + <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> + <translation type="unfinished">Tá naisc amach teoranta do i2p (-onlynet=i2p) ach nà chuirtear -i2psam ar fáil</translation> + </message> + <message> + <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> + <translation type="unfinished">SáraÃonn méid an ionchuir an t-uasmheáchan. Bain triail as méid nÃos lú a sheoladh nó UTXO do sparán a chomhdhlúthú de láimh</translation> + </message> + <message> + <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">Nà chlúdaÃonn méid iomlán na monaà réamhroghnaithe sprioc an idirbhirt. Ceadaigh le do thoil ionchuir eile a roghnú go huathoibrÃoch nó cuir nÃos mó bonn san áireamh de láimh</translation> + </message> + <message> + <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> + <translation type="unfinished">ÉilÃonn an t-idirbheart ceann scrÃbe amháin de luach neamh-0, táille neamh-0, nó ionchur réamhroghnaithe</translation> + </message> + <message> + <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> + <translation type="unfinished">Theip ar bhailÃochtú a dhéanamh ar achomair UTXO. Atosaigh chun gnáthÃoslódáil na mbloc tosaigh a atosú, nó bain triail as pictiúr eile a lódáil.</translation> + </message> + <message> + <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> + <translation type="unfinished">Tá UTXOanna neamhdheimhnithe ar fáil, ach cruthaÃtear slabhra idirbheart a ndiúltóidh an mempool dóibh má dhéantar iad a chaitheamh</translation> + </message> + <message> + <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">Fuarthas iontráil oidhreachta gan choinne sa sparán tuairisceora. Sparán %s á lódáil + +Seans gur cuireadh isteach ar an sparán nó gur cruthaÃodh é le hintinn mhailÃseach.</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">Tuairisceoir neamhaitheanta aimsithe. Sparán %s á lódáil + +Seans gur cruthaÃodh an sparán ar leagan nÃos nuaÃ. +Bain triail as an leagan bogearraà is déanaà a rith.</translation> + </message> + <message> + <source> +Unable to cleanup failed migration</source> + <translation type="unfinished"> +Nà féidir an t-imirce theip a ghlanadh</translation> + </message> + <message> + <source> +Unable to restore backup of wallet.</source> + <translation type="unfinished"> +Nà féidir cúltaca an sparán a chur ar ais.</translation> + </message> + <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">Cuireadh isteach ar an bhfÃorú blocála</translation> + </message> + <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished">Nà chuirtear socrú cumraÃochta do %s i bhfeidhm ach ar lÃonra %s nuair atá sé sa rannán [%s].</translation> </message> @@ -3229,6 +4449,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Lódáil déanta</translation> </message> <message> + <source>Dump file %s does not exist.</source> + <translation type="unfinished">NÃl an comhad dumpála %s ann.</translation> + </message> + <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Earráid agus db txn á dhéanamh chun idirbhearta sparán a bhaint</translation> + </message> + <message> + <source>Error creating %s</source> + <translation type="unfinished">Earráid cruthaithe %s</translation> + </message> + <message> <source>Error initializing block database</source> <translation type="unfinished">Earráid ag túsú bunachar sonraà bloic</translation> </message> @@ -3261,18 +4493,114 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Earráid ag oscailt bunachar sonraà bloic</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">Earráid agus an comhad cumraÃochta á léamh: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">Earráid ag léamh ón mbunachar sonraÃ, ag múchadh.</translation> </message> <message> + <source>Error reading next record from wallet database</source> + <translation type="unfinished">Earráid agus an chéad taifead eile á léamh ón mbunachar sonraà sparán</translation> + </message> + <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Earráid agus db txn á thosú chun idirbhearta sparán a bhaint</translation> + </message> + <message> + <source>Error: Cannot extract destination from the generated scriptpubkey</source> + <translation type="unfinished">Earráid: Nà féidir an ceann scrÃbe a bhaint as an scriptpubkey ginte</translation> + </message> + <message> + <source>Error: Couldn't create cursor into database</source> + <translation type="unfinished">Earráid: NÃorbh fhéidir an cúrsóir a chruthú sa bhunachar sonraÃ</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> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">Earráid: Nà hionann seiceála Dumpfile. RÃomh %s, bhÃothas ag súil le %s</translation> + </message> + <message> + <source>Error: Failed to create new watchonly wallet</source> + <translation type="unfinished">Earráid: Theip ar chruthú sparán faire amháin nua</translation> + </message> + <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">Earráid: Fuair ​​​​tú eochair nach heicsidheachúlach Ã: %s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">Earráid: Fuair ​​tú luach nach heicsidheachúlach é: %s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">Earráid: Rith keypool amach, glaoigh ar keypoolrefill ar dtús</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">Earráid: Seiceáil in easnamh</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">Earráid: NÃl seoladh %s ar fáil.</translation> + </message> + <message> + <source>Error: This wallet already uses SQLite</source> + <translation type="unfinished">Earráid: Úsáideann an sparán seo SQLite cheana féin</translation> + </message> + <message> + <source>Error: This wallet is already a descriptor wallet</source> + <translation type="unfinished">Earráid: Is sparán tuairisceora é an sparán seo cheana féin</translation> + </message> + <message> + <source>Error: Unable to begin reading all records in the database</source> + <translation type="unfinished">Earráid: Nà féidir tosú ag léamh gach taifead sa bhunachar sonraÃ</translation> + </message> + <message> + <source>Error: Unable to make a backup of your wallet</source> + <translation type="unfinished">Earráid: Nà féidir cúltaca a dhéanamh de do sparán</translation> + </message> + <message> + <source>Error: Unable to parse version %u as a uint32_t</source> + <translation type="unfinished">Earráid: Nà féidir leagan%u a pharsáil mar uint32_t</translation> + </message> + <message> + <source>Error: Unable to read all records in the database</source> + <translation type="unfinished">Earráid: Nà féidir gach taifead sa bhunachar sonraà a léamh</translation> + </message> + <message> + <source>Error: Unable to read wallet's best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr sa sparán a léamh</translation> + </message> + <message> + <source>Error: Unable to remove watchonly address book data</source> + <translation type="unfinished">Earráid: Nà féidir sonraà leabhar seoltaà faire amháin a bhaint</translation> + </message> + <message> + <source>Error: Unable to write record to new wallet</source> + <translation type="unfinished">Earráid: Nà féidir taifead a scrÃobh chuig an sparán nua</translation> + </message> + <message> + <source>Error: Unable to write solvable wallet best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr ar an sparán intuaslagtha a scrÃobh</translation> + </message> + <message> + <source>Error: Unable to write watchonly wallet best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr le sparán faire amháin a scrÃobh</translation> + </message> + <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Earráid: theip ar chóip leabhar seoltaà do sparán %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Earráid: nà féidir idirbheart bunachar sonraà a chur i gcrÃch le haghaidh sparán %s</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Theip ar éisteacht ar aon phort. Úsáid -listen=0 más é seo atá uait.</translation> </message> @@ -3281,10 +4609,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Theip athscanadh ar an sparán le linn túsúchán</translation> </message> <message> + <source>Failed to start indexes, shutting down..</source> + <translation type="unfinished">Theip ar thús a chur leis na hinnéacsanna, dúnadh.</translation> + </message> + <message> <source>Failed to verify database</source> <translation type="unfinished">Theip ar fhÃorú an mbunachar sonraÃ</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Teip ag baint an idirbhirt: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">Tá an ráta táillà (%s) nÃos Ãsle ná an socrú Ãosta rátaà táille (%s).</translation> </message> @@ -3293,6 +4629,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Neamhaird ar sparán dhúbailt %s.</translation> </message> <message> + <source>Importing…</source> + <translation type="unfinished">à iompórtáil…</translation> + </message> + <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> <translation type="unfinished">Bloc geineasas mÃcheart nó nà aimsithe. datadir mÃcheart don lÃonra?</translation> </message> @@ -3301,10 +4641,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Theip ar seiceáil slánchiall túsúchán. Tá %s ag múchadh.</translation> </message> <message> + <source>Input not found or already spent</source> + <translation type="unfinished">Ionchur gan aimsiú nó caite cheana féin</translation> + </message> + <message> + <source>Insufficient dbcache for block verification</source> + <translation type="unfinished">Dbcache neamhleor le haghaidh fÃorú blocála</translation> + </message> + <message> <source>Insufficient funds</source> <translation type="unfinished">Neamhleor ciste</translation> </message> <message> + <source>Invalid -i2psam address or hostname: '%s'</source> + <translation type="unfinished">Seoladh neamhbhailà -i2psam nó óstainm: '%s'</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation type="unfinished">Seoladh neamhbhailà -onion nó óstainm: '%s'</translation> </message> @@ -3317,6 +4669,14 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Cead neamhbhailà P2P: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=1: '%s' (ar a laghad %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Suim neamhbhailà do -%s=<amount>: '%s'</translation> </message> @@ -3325,14 +4685,62 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Mascghréas neamhbhailà sonraithe sa geal-liosta: '%s'</translation> </message> <message> + <source>Invalid port specified in %s: '%s'</source> + <translation type="unfinished">Port neamhbhailà sonraithe i %s: '%s'</translation> + </message> + <message> + <source>Invalid pre-selected input %s</source> + <translation type="unfinished">Ionchur réamhroghnaithe %s neamhbhailÃ</translation> + </message> + <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">Theip ar éisteacht le naisc isteach (éisteacht ar ais earráid %s)</translation> + </message> + <message> + <source>Loading P2P addresses…</source> + <translation type="unfinished">Seoltaà P2P á lódáil…</translation> + </message> + <message> + <source>Loading banlist…</source> + <translation type="unfinished">Liosta toirmeasc á lódáil…</translation> + </message> + <message> + <source>Loading block index…</source> + <translation type="unfinished">Innéacs bloc á lódáil…</translation> + </message> + <message> + <source>Loading wallet…</source> + <translation type="unfinished">Sparán á lódáil…</translation> + </message> + <message> + <source>Missing amount</source> + <translation type="unfinished">Méid ar iarraidh</translation> + </message> + <message> + <source>Missing solving data for estimating transaction size</source> + <translation type="unfinished">Sonraà réitigh ar iarraidh le haghaidh meastachán a dhéanamh ar mhéid an idirbhirt</translation> + </message> + <message> <source>Need to specify a port with -whitebind: '%s'</source> <translation type="unfinished">Is gá port a shainiú le -whitebind: '%s'</translation> </message> <message> + <source>No addresses available</source> + <translation type="unfinished">NÃl aon seoltaà ar fáil</translation> + </message> + <message> <source>Not enough file descriptors available.</source> <translation type="unfinished">NÃl dóthain tuairisceoirà comhaid ar fáil.</translation> </message> <message> + <source>Not found pre-selected input %s</source> + <translation type="unfinished">NÃor aimsÃodh ionchur réamhroghnaithe %s</translation> + </message> + <message> + <source>Not solvable pre-selected input %s</source> + <translation type="unfinished">Nà féidir ionchur réamhroghnaithe %s a réiteach</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Nà féidir Bearradh a bheidh cumraithe le luach diúltach.</translation> </message> @@ -3341,10 +4749,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Tá an mód bearrtha neamh-chomhoiriúnach le -txindex.</translation> </message> <message> + <source>Pruning blockstore…</source> + <translation type="unfinished">Blocsiopa á bhearradh…</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation type="unfinished">Laghdú -maxconnections ó %d go %d, mar gheall ar shrianadh an chórais.</translation> </message> <message> + <source>Replaying blocks…</source> + <translation type="unfinished">Bloic á n-athsheinn…</translation> + </message> + <message> + <source>Rescanning…</source> + <translation type="unfinished">à athscanadh…</translation> + </message> + <message> <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> <translation type="unfinished">SQLiteDatabase: Theip ar rith ráiteas chun an bunachar sonraà a fhÃorú: %s</translation> </message> @@ -3385,10 +4805,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃl eolaire bloic shonraithe "%s" ann.</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">NÃl comhadlann sonraà sonraithe "%s" ann.</translation> + </message> + <message> + <source>Starting network threads…</source> + <translation type="unfinished">Snáitheanna lÃonra á dtosú…</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Tá an cód foinseach ar fáil ó %s.</translation> </message> <message> + <source>The specified config file %s does not exist</source> + <translation type="unfinished">NÃl an comhad cumraÃochta sonraithe %s ann</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation type="unfinished">Tá suim an idirbhirt ró-bheag chun an táille a Ãoc</translation> </message> @@ -3409,6 +4841,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Seo an táille idirbhirt a Ãocfaidh tú má sheolann tú idirbheart.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Nà bhaineann an t-idirbheart %s leis an sparán seo</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Méid an idirbhirt ró-bheag</translation> </message> @@ -3417,14 +4853,26 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃor cheart go mbeadh suimeanna idirbhirt diúltach</translation> </message> <message> + <source>Transaction change output index out of range</source> + <translation type="unfinished">Innéacs aschuir athraithe idirbhirt as raon</translation> + </message> + <message> <source>Transaction must have at least one recipient</source> <translation type="unfinished">Caithfidh ar a laghad faighteoir amháin a bheith ag idirbheart</translation> </message> <message> + <source>Transaction needs a change address, but we can't generate it.</source> + <translation type="unfinished">TeastaÃonn seoladh athraithe ón idirbheart, ach nà féidir linn é a ghiniúint.</translation> + </message> + <message> <source>Transaction too large</source> <translation type="unfinished">Idirbheart ró-mhór</translation> </message> <message> + <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> + <translation type="unfinished">Nà féidir cuimhne a leithdháileadh le haghaidh -maxsigcachesize: '%s' MiB</translation> + </message> + <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Nà féidir ceangal le %s ar an rÃomhaire seo (thug ceangail earráid %s ar ais)</translation> </message> @@ -3437,6 +4885,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃorbh fhéidir cruthú comhad PID '%s': %s</translation> </message> <message> + <source>Unable to find UTXO for external input</source> + <translation type="unfinished">Nà féidir UTXO a aimsiú le haghaidh ionchur seachtrach</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation type="unfinished">Nà féidir eochracha tosaigh a ghiniúint</translation> </message> @@ -3445,10 +4897,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir eochracha a ghiniúint</translation> </message> <message> + <source>Unable to open %s for writing</source> + <translation type="unfinished">Nà féidir %s a oscailt chun scrÃobh</translation> + </message> + <message> + <source>Unable to parse -maxuploadtarget: '%s'</source> + <translation type="unfinished">Nà féidir a pharsáil -maxuploadtarget: '%s'</translation> + </message> + <message> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished">Nà féidir freastalaà HTTP a thosú. Féach loga dÃfhabhtúcháin le tuilleadh sonraÃ.</translation> </message> <message> + <source>Unable to unload the wallet before migrating</source> + <translation type="unfinished">Nà féidir an sparán a dhÃluchtú roimh aistriú</translation> + </message> + <message> <source>Unknown -blockfilterindex value %s.</source> <translation type="unfinished">Luach -blockfilterindex %s anaithnid.</translation> </message> @@ -3465,16 +4929,56 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">LÃonra anaithnid sonraithe san -onlynet: '%s'</translation> </message> <message> + <source>Unknown new rules activated (versionbit %i)</source> + <translation type="unfinished">Rialacha nua anaithnid curtha i ngnÃomh (leagan giotán %ii)</translation> + </message> + <message> + <source>Unsupported global logging level %s=%s. Valid values: %s.</source> + <translation type="unfinished">Leibhéal logála domhanda nach dtacaÃtear leis %s=%s. Luachanna bailÃ: %s.</translation> + </message> + <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Theip ar chruthú comhaid sparán: %s</translation> + </message> + <message> + <source>acceptstalefeeestimates is not supported on %s chain.</source> + <translation type="unfinished">nà thacaÃtear le acceptstalefeeestimates ar slabhra %s.</translation> + </message> + <message> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished">Catagóir logáil gan tacaÃocht %s=%s.</translation> </message> <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">Earráid: NÃorbh fhéidir watch amháin tx %s a chur le sparán faire amháin</translation> + </message> + <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Earráid: NÃorbh fhéidir idirbhearta faire amháin a scriosadh.</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> <message> + <source>Verifying blocks…</source> + <translation type="unfinished">Bloic á bhfÃorú…</translation> + </message> + <message> + <source>Verifying wallet(s)…</source> + <translation type="unfinished">Sparán(aÃ) á fhÃorú…</translation> + </message> + <message> <source>Wallet needed to be rewritten: restart %s to complete</source> <translation type="unfinished">Ba ghá an sparán a athscrÃobh: atosaigh %s chun crÃochnú</translation> </message> - </context> + <message> + <source>Settings file could not be read</source> + <translation type="unfinished">NÃorbh fhéidir an comhad socruithe a léamh</translation> + </message> + <message> + <source>Settings file could not be written</source> + <translation type="unfinished">NÃorbh fhéidir an comhad socruithe a scrÃobh</translation> + </message> +</context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ga_IE.ts b/src/qt/locale/bitcoin_ga_IE.ts index df252f82d5..174907f094 100644 --- a/src/qt/locale/bitcoin_ga_IE.ts +++ b/src/qt/locale/bitcoin_ga_IE.ts @@ -211,10 +211,22 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Bhà an pasfhrása iontráilte le haghaidh dÃchriptiú an sparán mÃcheart.</translation> </message> <message> + <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">Tá an pasfhrása a iontráladh le haghaidh dÃchriptithe an sparán mÃcheart. Tá carachtar nialasach ann (ie - beart nialasach). Má socraÃodh an pasfhrása le leagan den bhogearra seo roimh 25.0, bain triail eile as gan ach na carachtair suas go dtà — ach gan a bheith san áireamh — an chéad charachtar null. Má éirÃonn leis seo, socraigh pasfhrása nua le do thoil chun an cheist seo a sheachaint amach anseo.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">AthraÃodh pasfhrása sparán go rathúil.</translation> </message> <message> + <source>Passphrase change failed</source> + <translation type="unfinished">Theip ar athrú pasfhocail</translation> + </message> + <message> + <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">Tá an seanphasfhrása a cuireadh isteach le haghaidh dÃchriptithe an sparán mÃcheart. Tá carachtar nialasach ann (ie - beart nialasach). Má socraÃodh an pasfhrása le leagan den bhogearra seo roimh 25.0, bain triail eile as gan ach na carachtair suas go dtà — ach gan a bheith san áireamh — an chéad charachtar null.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Rabhadh: Tá an eochair Glas Ceannlitreacha ar!</translation> </message> @@ -233,21 +245,59 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>BitcoinApplication</name> <message> + <source>Runaway exception</source> + <translation type="unfinished">Eisceacht runaway</translation> + </message> + <message> <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> <translation type="unfinished">Tharla earráid mharfach. Nà féidir le %1 leanúint ar aghaidh go sábháilte agus scoirfidh sé.</translation> </message> - </context> + <message> + <source>Internal error</source> + <translation type="unfinished">Earráid inmheánach</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">Tharla earráid inmheánach. Déanfaidh %1 iarracht leanúint ar aghaidh go sábháilte. Is fabht gan choinne é seo ar féidir a thuairisciú mar a thuairiscÃtear thÃos.</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">Ar mhaith leat socruithe a athshocrú go luachanna réamhshocraithe, nó deireadh a chur leis gan athruithe a dhéanamh?</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">Tharla earráid mharfach. Cinntigh go bhfuil an comhad socruithe inscrÃofa, nó bain triail as rith le -nosettings.</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Earráid: %1</translation> </message> <message> + <source>%1 didn't yet exit safely…</source> + <translation type="unfinished">NÃor scoir %1 go sábháilte fós…</translation> + </message> + <message> <source>unknown</source> <translation type="unfinished">neamhaithnid</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Leabaithe "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Cló réamhshocraithe an chórais "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Saincheaptha…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Suim</translation> </message> @@ -256,6 +306,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Iontráil seoladh Bitcoin (m.sh.%1)</translation> </message> <message> + <source>Unroutable</source> + <translation type="unfinished">Dothreoraithe</translation> + </message> + <message> + <source>Onion</source> + <comment>network name</comment> + <extracomment>Name of Tor network in peer info</extracomment> + <translation type="unfinished">Oinniún</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">Isteach</translation> @@ -266,6 +326,31 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Amach</translation> </message> <message> + <source>Full Relay</source> + <extracomment>Peer connection type that relays all network information.</extracomment> + <translation type="unfinished">SealaÃocht Iomlán</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">SealaÃocht Bloc</translation> + </message> + <message> + <source>Manual</source> + <extracomment>Peer connection type established manually through one of several methods.</extracomment> + <translation type="unfinished">Lámhleabhar</translation> + </message> + <message> + <source>Feeler</source> + <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> + <translation type="unfinished">Fearacht</translation> + </message> + <message> + <source>Address Fetch</source> + <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> + <translation type="unfinished">Seoladh Fetch</translation> + </message> + <message> <source>%1 d</source> <translation type="unfinished">%1 l</translation> </message> @@ -288,41 +373,41 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n soicind(Ã)</numerusform> + <numerusform>%n soicind(Ã)</numerusform> + <numerusform>%n soicind(Ã)</numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n nóiméad(a)</numerusform> + <numerusform>%n nóiméad(a)</numerusform> + <numerusform>%n nóiméad(a)</numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n uair(eanta)</numerusform> + <numerusform>%n uair(eanta)</numerusform> + <numerusform>%n uair(eanta)</numerusform> </translation> </message> <message numerus="yes"> <source>%n day(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n lá(/a)</numerusform> + <numerusform>%n lá(/a)</numerusform> + <numerusform>%n lá(/a)</numerusform> </translation> </message> <message numerus="yes"> <source>%n week(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n seachtain(/a)</numerusform> + <numerusform>%n seachtain(/a)</numerusform> + <numerusform>%n seachtain(/a)</numerusform> </translation> </message> <message> @@ -332,9 +417,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n year(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n bliain(/a)</numerusform> + <numerusform>%n bliain(/a)</numerusform> + <numerusform>%n bliain(/a)</numerusform> </translation> </message> </context> @@ -381,6 +466,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cruthaigh sparán nua</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished">&Ãoslaghdaigh</translation> + </message> + <message> <source>Wallet:</source> <translation type="unfinished">Sparán:</translation> </message> @@ -414,18 +503,62 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Glac</translation> </message> <message> + <source>&Options…</source> + <translation type="unfinished">&Roghanna…</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Criptigh Sparán…</translation> + </message> + <message> <source>Encrypt the private keys that belong to your wallet</source> <translation type="unfinished">Criptigh na heochracha prÃobháideacha a bhaineann le do sparán</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Sparán Cúltaca…</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&Athraigh Pasfhocal…</translation> + </message> + <message> + <source>Sign &message…</source> + <translation type="unfinished">SÃnigh &teachtaireacht…</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> <translation type="unfinished">SÃnigh teachtaireachtaà le do sheoltaà Bitcoin chun a chruthú gur leat iad</translation> </message> <message> + <source>&Verify message…</source> + <translation type="unfinished">&FÃoraigh teachtaireacht…</translation> + </message> + <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> <translation type="unfinished">Teachtaireachtaà a fhÃorú lena chinntiú go raibh siad sÃnithe le seoltaà sainithe Bitcoin</translation> </message> <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&Lódáil PSBT ón gcomhad…</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">Oscail &URI…</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">Dún Sparán…</translation> + </message> + <message> + <source>Create Wallet…</source> + <translation type="unfinished">Cruthaigh Sparán…</translation> + </message> + <message> + <source>Close All Wallets…</source> + <translation type="unfinished">Dún Gach Sparán…</translation> + </message> + <message> <source>&File</source> <translation type="unfinished">&Comhad</translation> </message> @@ -442,6 +575,26 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Barra uirlisà cluaisÃnÃ</translation> </message> <message> + <source>Syncing Headers (%1%)…</source> + <translation type="unfinished">Ceanntásca á Sioncronú (%1 %)…</translation> + </message> + <message> + <source>Synchronizing with network…</source> + <translation type="unfinished">Ag sioncronú le lÃonra…</translation> + </message> + <message> + <source>Indexing blocks on disk…</source> + <translation type="unfinished">Bloic á n-innéacsú ar an diosca…</translation> + </message> + <message> + <source>Processing blocks on disk…</source> + <translation type="unfinished">Bloic ar diosca á bpróiseáil…</translation> + </message> + <message> + <source>Connecting to peers…</source> + <translation type="unfinished">Ag nascadh le piaraÃ…</translation> + </message> + <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished">Iarr ÃocaÃochtaà (gineann cóid QR agus bitcoin: URIs)</translation> </message> @@ -460,9 +613,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> + <numerusform>Próiseáladh %n bloc de stair na n-idirbheart.</numerusform> </translation> </message> <message> @@ -470,6 +623,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 taobh thiar</translation> </message> <message> + <source>Catching up…</source> + <translation type="unfinished">Ag teacht suas…</translation> + </message> + <message> <source>Last received block was generated %1 ago.</source> <translation type="unfinished">Gineadh an bloc deireanach a fuarthas %1 ó shin.</translation> </message> @@ -498,6 +655,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Lódáil Idirbheart Bitcoin SÃnithe go Páirteach</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Luchtaigh PSBT ón &gearrthaisce…</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Lódáil Idirbheart Bitcoin SÃnithe go Páirteach ón gearrthaisce</translation> </message> @@ -534,10 +695,28 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Dún spará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">Athchóirigh Sparán…</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">Athchóirigh sparán ó chomhad cúltaca</translation> + </message> + <message> <source>Close all wallets</source> <translation type="unfinished">Dún gach sparán</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Imirce Sparán</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Imirce sparán</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished">Taispeáin an %1 teachtaireacht chabhrach chun liosta a fháil de roghanna Bitcoin lÃne na n-orduithe féideartha</translation> </message> @@ -558,6 +737,21 @@ 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 Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Sonraà Sparán</translation> + </message> + <message> + <source>Load Wallet Backup</source> + <extracomment>The title for Restore Wallet File Windows</extracomment> + <translation type="unfinished">Luchtaigh Cúltaca Sparán</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">Athchóirigh Sparán</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> @@ -578,16 +772,56 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>%1 client</source> <translation type="unfinished">%1 cliaint</translation> </message> + <message> + <source>&Hide</source> + <translation type="unfinished">&Folaigh</translation> + </message> + <message> + <source>S&how</source> + <translation type="unfinished">S&conas</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 nasc(Ã) gnÃomhacha le lÃonra Bitcoin.</numerusform> + <numerusform>%n nasc(Ã) gnÃomhacha le lÃonra Bitcoin.</numerusform> + <numerusform>%n nasc(Ã) gnÃomhacha le lÃonra 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">Cliceáil le haghaidh tuilleadh gnÃomhartha.</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">Taispeáin cluaisÃn PiaraÃ</translation> + </message> + <message> + <source>Disable network activity</source> + <extracomment>A context menu item.</extracomment> + <translation type="unfinished">DÃchumasaigh gnÃomhaÃocht lÃonra</translation> + </message> + <message> + <source>Enable network activity</source> + <extracomment>A context menu item. The network activity was disabled previously.</extracomment> + <translation type="unfinished">Cumasaigh gnÃomhaÃocht lÃonra</translation> + </message> + <message> + <source>Pre-syncing Headers (%1%)…</source> + <translation type="unfinished">Ceanntásca a réamhshioncronú (%1 %)…</translation> + </message> + <message> + <source>Error creating wallet</source> + <translation type="unfinished">Earráid agus sparán á chruthú</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">Nà féidir sparán nua a chruthú, tiomsaÃodh na bogearraà gan tacaÃocht sqlite (riachtanach le haghaidh sparán tuairisceora)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Earráid: %1</translation> </message> @@ -742,6 +976,30 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil suim</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">Cóipeáil idirbheart & ID agus innéacs aschuir</translation> + </message> + <message> + <source>L&ock unspent</source> + <translation type="unfinished">L&ocáil neamhchaite</translation> + </message> + <message> + <source>&Unlock unspent</source> + <translation type="unfinished">&DÃghlasáil neamhchaite</translation> + </message> + <message> <source>Copy quantity</source> <translation type="unfinished">Cóipeáil méid</translation> </message> @@ -802,7 +1060,79 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>Create wallet warning</source> <translation type="unfinished">Rabhadh cruthú sparán</translation> </message> - </context> + <message> + <source>Can't list signers</source> + <translation type="unfinished">Nà féidir sÃnitheoirà a liostú</translation> + </message> + <message> + <source>Too many external signers found</source> + <translation type="unfinished">Fuarthas an iomarca sÃnitheoirà seachtracha</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">Luchtaigh Sparán</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">Sparán á lódáil…</translation> + </message> +</context> +<context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Imirce sparán</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">An bhfuil tú cinnte gur mian leat an sparán <i>%1 </i>?</translation> + </message> + <message> + <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> + <translation type="unfinished">Má dhéantar an sparán a aistriú, déanfar an sparán seo a thiontú go sparán tuairisceora amháin nó nÃos mó. Beidh gá le cúltaca sparán nua. +Má tá aon scripteanna faire amháin sa sparán seo, cruthófar sparán nua ina mbeidh na scripteanna faire amháin sin. +Má tá aon scripteanna intuaslagtha ach nach bhfuil faire orthu sa sparán seo, cruthófar sparán difriúil agus nua ina mbeidh na scripteanna sin. + +Cruthóidh an próiseas imirce cúltaca den sparán roimh imirce. Ainmneofar an comhad cúltaca seo <wallet name>-<timestamp>.legacy.bak agus is féidir é a fháil san eolaire don sparán seo. I gcás imirce mÃcheart, is féidir an cúltaca a chur ar ais leis an bhfeidhmiúlacht "Athchóirigh Sparán".</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Imirce Sparán</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">Sparán á Ascnamh <b>%1</b>…</translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">D'éirigh le haistriú an sparán '%1'.</translation> + </message> + <message> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">AistrÃodh scripteanna faire amháin go sparán nua darb ainm '%1'.</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">AistrÃodh scripteanna intuaslagtha ach nach bhfuiltear ag faire orthu go sparán nua darb ainm '%1'.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">Theip ar an imirce</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">D'éirigh leis an Imirce</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> <message> @@ -822,7 +1152,40 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> <translation type="unfinished">Oscail Sparán</translation> </message> - </context> + <message> + <source>Opening Wallet <b>%1</b>…</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">Sparán Oscailte<b>%1</b>…</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">Athchóirigh Sparán</translation> + </message> + <message> + <source>Restoring Wallet <b>%1</b>…</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">Sparán á Athchóiriú<b>%1</b>…</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">Theip ar athchóiriú an sparán</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">Athchóirigh rabhadh sparán</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">Athchóirigh teachtaireacht sparán</translation> + </message> +</context> <context> <name>WalletController</name> <message> @@ -853,6 +1216,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cruthaigh Sparán</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Tá tú céim amháin ar shiúl ó chruthú do sparán nua!</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">Tabhair ainm le do thoil agus, más mian leat, cumasaigh aon ardroghanna</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Ainm Sparán</translation> </message> @@ -889,10 +1260,23 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Déan Sparán Glan</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">Bain úsáid as gléas sÃnithe seachtrach cosúil le sparán crua-earraÃ. Cumraigh an script sÃnitheora sheachtraigh i sainroghanna an sparán ar dtús.</translation> + </message> + <message> + <source>External signer</source> + <translation type="unfinished">SÃnitheoir seachtrach</translation> + </message> + <message> <source>Create</source> <translation type="unfinished">Cruthaigh</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">Tiomsaithe gan tacaÃocht sÃnithe seachtrach (riachtanach le haghaidh sÃniú seachtrach)</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -972,9 +1356,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>%n GB de spás ar fáil</numerusform> + <numerusform>%n GB de spás ar fáil</numerusform> + <numerusform>%n GB de spás ar fáil</numerusform> </translation> </message> <message numerus="yes"> @@ -994,6 +1378,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </translation> </message> <message> + <source>Choose data directory</source> + <translation type="unfinished">Roghnaigh eolaire sonraÃ</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> </message> @@ -1005,9 +1393,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</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>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> + <numerusform>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> + <numerusform>(leor chun cúltacaà a aischur %n lá(laethanta) d'aois)</numerusform> </translation> </message> <message> @@ -1039,6 +1427,10 @@ 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>Limit block chain storage to</source> + <translation type="unfinished">Teorainn a chur le blocshlabhra stórála go</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> @@ -1047,6 +1439,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Tá an sioncrónú tosaigh seo an-dhian, agus d’fhéadfadh sé fadhbanna crua-earraà a nochtadh le do rÃomhaire nach tugadh faoi deara roimhe seo. Gach uair a ritheann tú %1, leanfaidh sé ar aghaidh ag Ãoslódáil san áit ar fhág sé as.</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">Nuair a chliceálann tú OK, tosóidh %1 ag Ãosluchtú agus ag próiseáil slabhra iomlán %4 (%2 GB) ag tosú leis na hidirbhearta is luaithe i %3 nuair a seoladh %4 ar dtús.</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">Má roghnaigh tú stóráil blocshlabhra a theorannú (bearradh), fós caithfear na sonraà stairiúla a Ãoslódáil agus a phróiseáil, ach scriosfar iad ina dhiaidh sin chun d’úsáid diosca a choinneáil Ãseal.</translation> </message> @@ -1077,6 +1473,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>ShutdownWindow</name> <message> + <source>%1 is shutting down…</source> + <translation type="unfinished">Tá %1 ag múchadh…</translation> + </message> + <message> <source>Do not shut down the computer until this window disappears.</source> <translation type="unfinished">Ná múch an rÃomhaire go dtà go n-imÃonn an fhuinneog seo.</translation> </message> @@ -1100,6 +1500,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">LÃon na mbloic fágtha</translation> </message> <message> + <source>Unknown…</source> + <translation type="unfinished">Anaithnid…</translation> + </message> + <message> + <source>calculating…</source> + <translation type="unfinished">ag rÃomh…</translation> + </message> + <message> <source>Last block time</source> <translation type="unfinished">Am bloc deireanach</translation> </message> @@ -1123,7 +1531,15 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</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">Tá %1 ag sioncronú faoi láthair. Déanfaidh sé é a Ãoslódáil agus a fÃorú ar ceanntásca agus bloic ó phiaraà go dtà barr an blocshlabhra.</translation> </message> - </context> + <message> + <source>Unknown. Syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Anaithnid. Ceanntásca á Sioncronú (%1, %2 %)…</translation> + </message> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Anaithnid. Ceanntásca a Réamhshioncronú (%1, %2 %)…</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -1155,6 +1571,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Tosaigh %1 ar logáil isteach an chórais</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">LaghdaÃtear go mór an spás diosca a theastaÃonn chun idirbhearta a stóráil má dhéantar bearradh a chumasú. Tá gach bloc fós bailÃochtaithe go hiomlán. Chun an socrú seo a thabhairt ar ais nà mór an blockchain iomlán a athÃoslódáil.</translation> + </message> + <message> <source>Size of &database cache</source> <translation type="unfinished">Méid taisce &bunachar sonraÃ</translation> </message> @@ -1163,6 +1583,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">LÃon snáitheanna &fÃorú scripte</translation> </message> <message> + <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">Conair iomlán chuig script comhoiriúnach %1 (m.sh. C:\Downloads\hwi.exe nó /Users/you/Downloads/hwi.py). Tabhair aire: is féidir le malware do bhoinn a ghoid!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">Seoladh IP an seachfhreastalaà (m.sh. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -1175,6 +1599,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ãoslaghdaigh in ionad scoir an feidhmchlár nuair a bhÃonn an fhuinneog dúnta. Nuair a chumasófar an rogha seo, nà dhúnfar an feidhmchlár ach amháin tar éis Scoir a roghnú sa roghchlár.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Cló sa chluaisÃn Forbhreathnú:</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line:</source> + <translation type="unfinished">Tá na roghanna atá socraithe sa dialóg seo sáraithe ag an lÃne ordaithe:</translation> + </message> + <message> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished">Oscail an comhad cumraÃochta %1 ón eolaire oibre.</translation> </message> @@ -1203,14 +1635,44 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">TeastaÃonn an blocshlabhra iomlán a Ãoslódáil arÃs chun an socrú seo a fhilleadh.</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">Uasmhéid taisce bunachar sonraÃ. Is féidir le taisce nÃos mó cur le sioncrónú nÃos tapúla, agus ina dhiaidh sin nà bhÃonn an tairbhe chomh soiléir don chuid is mó de chásanna úsáide. Laghdófar úsáid chuimhne má laghdaÃtear méid an taisce. Roinntear cuimhne mempool neamhúsáidte don taisce seo.</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">Socraigh lÃon na snáitheanna fÃoraithe scripte. FreagraÃonn luachanna diúltacha do lÃon na gcroÃthe is mian leat a fhágáil saor sa chóras.</translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished">(0 = uath, <0 = fág an méid sin cóir saor)</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">Ligeann sé seo duit féin nó d’uirlis trÃú páirtà cumarsáid a dhéanamh leis an nód trà orduithe ordú-lÃne agus JSON-RPC.</translation> + </message> + <message> + <source>Enable R&PC server</source> + <extracomment>An Options window setting to enable the RPC server.</extracomment> + <translation type="unfinished">Cumasaigh freastalaà R&PC</translation> + </message> + <message> <source>W&allet</source> <translation type="unfinished">Sp&arán</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">Cibé an táille a dhealú ón méid a shocrú mar réamhshocrú nó nach bhfuil.</translation> + </message> + <message> + <source>Subtract &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">Dealaigh &táille ón méid de réir réamhshocraithe</translation> + </message> + <message> <source>Expert</source> <translation type="unfinished">Saineolach</translation> </message> @@ -1227,6 +1689,24 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Caith &sóinseáil neamhdheimhnithe</translation> </message> <message> + <source>Enable &PSBT controls</source> + <extracomment>An options window setting to enable PSBT controls.</extracomment> + <translation type="unfinished">Cumasaigh & rialuithe 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">Cibé ar cheart rialuithe PSBT a thaispeáint.</translation> + </message> + <message> + <source>External Signer (e.g. hardware wallet)</source> + <translation type="unfinished">SÃnitheoir Seachtrach (m.sh. sparán crua-earraÃ)</translation> + </message> + <message> + <source>&External signer script path</source> + <translation type="unfinished">&Conair scripte sÃnithe seachtraÃ</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">Oscail port cliant Bitcoin go huathoibrÃoch ar an ródaire. Nà oibrÃonn sé seo ach nuair a thacaÃonn do ródaire le UPnP agus nuair a chumasaÃtear é.</translation> </message> @@ -1235,6 +1715,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Mapáil port ag úsáid &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">Oscail calafort cliant Bitcoin go huathoibrÃoch ar an ródaire. Nà oibrÃonn sé seo ach amháin nuair a thacaÃonn do ródaire le NAT-PMP agus go bhfuil sé cumasaithe. D'fhéadfadh an port seachtrach a bheith randamach.</translation> + </message> + <message> + <source>Map port using NA&T-PMP</source> + <translation type="unfinished">Port léarscáil le NA&T-PMP</translation> + </message> + <message> <source>Accept connections from outside.</source> <translation type="unfinished">Glac le naisc ón taobh amuigh.</translation> </message> @@ -1267,6 +1755,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Fuinneog</translation> </message> <message> + <source>Show the icon in the system tray.</source> + <translation type="unfinished">Taispeáin an deilbhÃn i dtráidire an chórais.</translation> + </message> + <message> + <source>&Show tray icon</source> + <translation type="unfinished">&Taispeáin Ãocón an tráidire</translation> + </message> + <message> <source>Show only a tray icon after minimizing the window.</source> <translation type="unfinished">Ná taispeáin ach deilbhÃn tráidire t'éis an fhuinneog a Ãoslaghdú.</translation> </message> @@ -1299,6 +1795,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Roghnaigh an t-aonad foroinnte réamhshocraithe le taispeáint sa chomhéadan agus nuair a sheoltar boinn.</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">URLanna trÃú páirtà (m.sh. taiscéalaà bloc) atá le feiceáil sa chluaisÃn idirbheart mar mhÃreanna roghchláir comhthéacs. Cuirtear hais idirbhirt in ionad%s sa URL. Déantar URLanna iolracha a dheighilt le barra ingearach |.</translation> + </message> + <message> + <source>&Third-party transaction URLs</source> + <translation type="unfinished">URLanna idirbheart trÃú páirtÃ</translation> + </message> + <message> <source>Whether to show coin control features or not.</source> <translation type="unfinished">Gnéithe rialúchán bonn a thaispeáint nó nach.</translation> </message> @@ -1319,6 +1823,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">&Cealaigh</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">Tiomsaithe gan tacaÃocht sÃnithe seachtrach (riachtanach le haghaidh sÃniú seachtrach)</translation> + </message> + <message> <source>default</source> <translation type="unfinished">réamhshocrú</translation> </message> @@ -1337,6 +1846,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Atosú cliant ag teastáil chun athruithe a ghnÃomhachtú.</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">Déanfar cúltaca de na socruithe reatha ag "%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">Múchfar an cliant. Ar mhaith leat dul ar aghaidh?</translation> @@ -1352,6 +1866,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Úsáidtear an comhad cumraÃochta chun ardroghanna úsáideora a shonrú a sháraÃonn socruithe GUI. Freisin, sáróidh aon roghanna lÃne na n-orduithe an comhad cumraÃochta seo.</translation> </message> <message> + <source>Continue</source> + <translation type="unfinished">Leanúint ar aghaidh</translation> + </message> + <message> <source>Cancel</source> <translation type="unfinished">Cealaigh</translation> </message> @@ -1373,6 +1891,13 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </message> </context> <context> + <name>OptionsModel</name> + <message> + <source>Could not read setting "%1", %2.</source> + <translation type="unfinished">NÃorbh fhéidir socrú "%1", %2 a léamh.</translation> + </message> +</context> +<context> <name>OverviewPage</name> <message> <source>Form</source> @@ -1454,6 +1979,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>PSBTOperationsDialog</name> <message> + <source>PSBT Operations</source> + <translation type="unfinished">OibrÃochtaà PSBT</translation> + </message> + <message> <source>Sign Tx</source> <translation type="unfinished">SÃnigh Tx</translation> </message> @@ -1466,6 +1995,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil chuig Gearrthaisce</translation> </message> <message> + <source>Save…</source> + <translation type="unfinished">Sábháil…</translation> + </message> + <message> <source>Close</source> <translation type="unfinished">Dún</translation> </message> @@ -1478,6 +2011,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Theip ar sÃniú idirbheart: %1</translation> </message> <message> + <source>Cannot sign inputs while wallet is locked.</source> + <translation type="unfinished">Nà féidir ionchuir a shÃniú agus an sparán glasáilte.</translation> + </message> + <message> <source>Could not sign any more inputs.</source> <translation type="unfinished">NÃorbh fhéidir nÃos mó ionchuir a shÃniú.</translation> </message> @@ -1510,10 +2047,19 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Sábháil Sonraà Idirbheart</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">Idirbheart Páirt-SÃnithe (Dénártha)</translation> + </message> + <message> <source>PSBT saved to disk.</source> <translation type="unfinished">IBSP sábháilte ar dhiosca.</translation> </message> <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">Seoltar %1 go %2</translation> + </message> + <message> <source>own address</source> <translation type="unfinished">seoladh féin</translation> </message> @@ -1546,6 +2092,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Tá sÃni(ú/the) fós ag teastáil ón idirbheart.</translation> </message> <message> + <source>(But no wallet is loaded.)</source> + <translation type="unfinished">(Ach nÃl aon sparán luchtaithe.)</translation> + </message> + <message> <source>(But this wallet cannot sign transactions.)</source> <translation type="unfinished">(Ach nà féidir leis an sparán seo idirbhearta a shÃniú.)</translation> </message> @@ -1581,6 +2131,14 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Nà URI bailà é 'bitcoin://'. Úsáid 'bitcoin:' ina ionad.</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à féidir iarratas ÃocaÃochta a phróiseáil toisc nach dtacaÃtear le BIP70. +De bharr lochtanna slándála forleathan in BIP70, moltar go láidir neamhaird a dhéanamh d’aon treoracha ceannaithe chun sparán a athrú. +Má tá an earráid seo á fáil agat ba cheart duit iarraidh ar an dÃoltóir URI atá comhoiriúnach le BIP21 a sholáthar.</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">Nà féidir URI a pharsáil! Is féidir le seoladh neamhbhailà Bitcoin nó paraiméadair URI drochfhoirmithe a bheith mar an chúis.</translation> </message> @@ -1597,6 +2155,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">GnÃomhaire Úsáideora</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">PiaraÃ</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">Aois</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">Treo</translation> @@ -1640,6 +2208,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>QRImageWidget</name> <message> + <source>&Save Image…</source> + <translation type="unfinished">&Sábháil Ãomhá…</translation> + </message> + <message> <source>&Copy Image</source> <translation type="unfinished">&Cóipeáil Ãomhá</translation> </message> @@ -1659,7 +2231,12 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <source>Save QR Code</source> <translation type="unfinished">Sabháil cód 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">Ãomhá PNG</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> @@ -1759,10 +2336,34 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Roghnaigh piara chun faisnéis mhionsonraithe a fheiceáil.</translation> </message> <message> + <source>The transport layer version: %1</source> + <translation type="unfinished">Leagan na sraithe iompair: %1</translation> + </message> + <message> + <source>Transport</source> + <translation type="unfinished">Iompar</translation> + </message> + <message> + <source>The BIP324 session ID string in hex, if any.</source> + <translation type="unfinished">Teaghrán ID an tseisiúin BIP324 i heicsidheachúlach, más ann dó.</translation> + </message> + <message> + <source>Session ID</source> + <translation type="unfinished">Aitheantas an tseisiúin</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Leagan</translation> </message> <message> + <source>Whether we relay transactions to this peer.</source> + <translation type="unfinished">Cibé an ndéanaimid idirbhearta a athsheoladh chuig an bpiaraà seo.</translation> + </message> + <message> + <source>Transaction Relay</source> + <translation type="unfinished">Leaschraolacháin Idirbheart</translation> + </message> + <message> <source>Starting Block</source> <translation type="unfinished">Bloc Tosaigh</translation> </message> @@ -1775,6 +2376,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Bloic Sioncronaithe</translation> </message> <message> + <source>Last Transaction</source> + <translation type="unfinished">Idirbheart Deiridh</translation> + </message> + <message> <source>The mapped Autonomous System used for diversifying peer selection.</source> <translation type="unfinished">An Córas Uathrialach mapáilte a úsáidtear chun roghnú piaraà a éagsúlú.</translation> </message> @@ -1783,6 +2388,36 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">CU Mapáilte</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">Cibé an gcuirfimid seoltaà chuig an bpiaraà seo.</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">SealaÃocht Seoladh</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">LÃon iomlán na seoltaà a fuarthas ón bpiaraà seo a próiseáladh (nà áirÃtear seoltaà a laghdaÃodh mar gheall ar theorannú rátaÃ).</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">LÃon iomlán na seoltaà a fuarthas ón bpiaraà seo a thit (nár próiseáladh) mar gheall ar theorannú rátaÃ.</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">Seoltaà Próiseáilte</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">Seoltaà Ráta-Teoranta</translation> + </message> + <message> <source>User Agent</source> <translation type="unfinished">GnÃomhaire Úsáideora</translation> </message> @@ -1811,14 +2446,47 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ceadanna</translation> </message> <message> + <source>The direction and type of peer connection: %1</source> + <translation type="unfinished">Treo agus cineál an naisc phiara: %1</translation> + </message> + <message> + <source>Direction/Type</source> + <translation type="unfinished">Treo/Cineál</translation> + </message> + <message> + <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> + <translation type="unfinished">An prótacal lÃonra a bhfuil an piara seo ceangailte trÃ: IPv4, IPv6, Oinniún, I2P, nó CJDNS.</translation> + </message> + <message> <source>Services</source> <translation type="unfinished">SeirbhÃsÃ</translation> </message> <message> + <source>High bandwidth BIP152 compact block relay: %1</source> + <translation type="unfinished">Bandaleithead ard BIP152 sealaÃochta bloc dhlúth: %1</translation> + </message> + <message> + <source>High Bandwidth</source> + <translation type="unfinished">Bandaleithid Ard</translation> + </message> + <message> <source>Connection Time</source> <translation type="unfinished">Am Ceangail</translation> </message> <message> + <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> + <translation type="unfinished">Tá achar ama caite ó fuarthas bloc úrscéil a rinne na seiceálacha bailÃochta tosaigh ón gcomhghleacaà seo.</translation> + </message> + <message> + <source>Last Block</source> + <translation type="unfinished">Bloc Deireanach</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">Chuaigh an t-am caite ó fuarthas idirbheart úrnua a glacadh isteach inár mempool ón bpiaraà seo.</translation> + </message> + <message> <source>Last Send</source> <translation type="unfinished">Seol Deireanach</translation> </message> @@ -1883,6 +2551,68 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Amach:</translation> </message> <message> + <source>Inbound: initiated by peer</source> + <extracomment>Explanatory text for an inbound peer connection.</extracomment> + <translation type="unfinished">Isteach: arna thionscnamh ag piaraÃ</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">SealaÃocht Iomlán Amach: réamhshocraithe</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">Leaschraolacháin Bloc Amach: nà athsheoltar idirbhearta ná seoltaÃ</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">Lámhleabhar Amach: curtha leis ag úsáid roghanna cumraÃochta RPC %1 nó %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">Feeler Amach: gearrthéarmach, le haghaidh seoltaà tástála</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">Faigh Seoladh Amach: gearrthéarmach, chun seoltaà a lorg</translation> + </message> + <message> + <source>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">bhrath: d’fhéadfadh v1 nó v2 a bheith i gcomhghleacaÃ</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: prótacal iompair gnáththéacs gan chriptiú</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: BIP324 prótacal iompair criptithe</translation> + </message> + <message> + <source>we selected the peer for high bandwidth relay</source> + <translation type="unfinished">roghnaigh muid an piaraà le haghaidh sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>the peer selected us for high bandwidth relay</source> + <translation type="unfinished">roghnaigh an piaraà sinn le haghaidh sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>no high bandwidth relay selected</source> + <translation type="unfinished">nÃor roghnaÃodh aon sealaÃochta bandaleithead ard</translation> + </message> + <message> + <source>&Copy address</source> + <extracomment>Context menu action to copy the address of a peer.</extracomment> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> <source>&Disconnect</source> <translation type="unfinished">&Scaoil</translation> </message> @@ -1891,6 +2621,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">1 &uair</translation> </message> <message> + <source>1 d&ay</source> + <translation type="unfinished">1 l&á</translation> + </message> + <message> <source>1 &week</source> <translation type="unfinished">1 &seachtain</translation> </message> @@ -1899,6 +2633,11 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">1 &bhliain</translation> </message> <message> + <source>&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">&Cóipeáil IP/Netmask</translation> + </message> + <message> <source>&Unban</source> <translation type="unfinished">&DÃchosc</translation> </message> @@ -1911,10 +2650,40 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ag rith ordú gan aon sparán</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Fuinneog nód - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Ag rith ordú ag úsáid sparán "%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">Fáilte go consól RPC %1. +Úsáid saigheada suas agus sÃos chun an stair a nascleanúint, agus %2 chun an scáileán a ghlanadh. +Úsáid %3 agus %4 chun an clómhéid a mhéadú nó a laghdú. +ClóscrÃobh %5 le haghaidh forbhreathnú ar na horduithe atá ar fáil. +Chun tuilleadh eolais a fháil faoin gconsól seo a úsáid, clóscrÃobh %6. + +%7 RABHADH: Bhà scamadóirà gnÃomhach, ag rá le húsáideoirà orduithe a chlóscrÃobh anseo, ag goid a n-inneachar sparán. Ná húsáid an consól seo gan iarmhairtà ordaithe a thuiscint go hiomlán.%8</translation> + </message> + <message> + <source>Executing…</source> + <extracomment>A console message indicating an entered command is currently being executed.</extracomment> + <translation type="unfinished">Ag rith…</translation> + </message> + <message> + <source>(peer: %1)</source> + <translation type="unfinished">(piara: %1)</translation> + </message> + <message> <source>via %1</source> <translation type="unfinished">trà %1</translation> </message> @@ -1939,6 +2708,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cosc do</translation> </message> <message> + <source>Never</source> + <translation type="unfinished">Riamh</translation> + </message> + <message> <source>Unknown</source> <translation type="unfinished">Anaithnid</translation> </message> @@ -2018,6 +2791,46 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil &URI</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &message</source> + <translation type="unfinished">Cóipeáil & teachtaireacht</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Bonn58 (Oidhreacht)</translation> + </message> + <message> + <source>Not recommended due to higher fees and less protection against typos.</source> + <translation type="unfinished">Nà mholtar mar gheall ar tháillà nÃos airde agus cosaint nÃos lú i gcoinne typos.</translation> + </message> + <message> + <source>Base58 (P2SH-SegWit)</source> + <translation type="unfinished">Base58 (P2SH- SegWit)</translation> + </message> + <message> + <source>Generates an address compatible with older wallets.</source> + <translation type="unfinished">Gineann seoladh atá comhoiriúnach le sparán nÃos sine.</translation> + </message> + <message> + <source>Generates a native segwit address (BIP-173). Some old wallets don't support it.</source> + <translation type="unfinished">Gineann sé seoladh segwit dúchais (BIP-173). Nà thacaÃonn roinnt sean-sparán leis.</translation> + </message> + <message> + <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> + <translation type="unfinished">Is uasghrádú é Bech32m (BIP-350) go Bech32, tá tacaÃocht sparán fós teoranta.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation type="unfinished">NÃorbh fhéidir sparán a dhÃghlasáil.</translation> </message> @@ -2029,6 +2842,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <context> <name>ReceiveRequestDialog</name> <message> + <source>Request payment to …</source> + <translation type="unfinished">Iarr ÃocaÃocht chuig…</translation> + </message> + <message> <source>Address:</source> <translation type="unfinished">Seoladh:</translation> </message> @@ -2057,6 +2874,18 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Cóipeáil &Seoladh</translation> </message> <message> + <source>&Verify</source> + <translation type="unfinished">&FÃoraigh</translation> + </message> + <message> + <source>Verify this address on e.g. a hardware wallet screen</source> + <translation type="unfinished">FÃoraigh an seoladh seo ar e.g. scáileán sparán crua-earraÃ</translation> + </message> + <message> + <source>&Save Image…</source> + <translation type="unfinished">&Sábháil Ãomhá…</translation> + </message> + <message> <source>Payment information</source> <translation type="unfinished">Faisnéis ÃocaÃochta</translation> </message> @@ -2187,10 +3016,26 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Glan gach réimse den fhoirm.</translation> </message> <message> + <source>Inputs…</source> + <translation type="unfinished">Ionchuir…</translation> + </message> + <message> + <source>Choose…</source> + <translation type="unfinished">Roghnaigh…</translation> + </message> + <message> <source>Hide transaction fee settings</source> <translation type="unfinished">Folaigh socruithe táillà idirbhirt</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">Sonraigh táille shaincheaptha in aghaidh an kB (1,000 beart) de mhéid fÃorúil an idirbhirt. + +Nóta: Ós rud é go rÃomhtar an táille ar bhonn in aghaidh an bheart, nà thabharfadh ráta táille "100 satoshis in aghaidh an kvB" le haghaidh méid idirbhirt 500 beart fÃorúil (leath de 1 kvB) táille ach 50 satoshis ar deireadh thiar.</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">Nuair a bhÃonn méid idirbhirt nÃos lú ná spás sna bloic, féadfaidh mianadóirà chomh maith le nóid athsheachadadh táille Ãosta a fhorfheidhmiú. Tá sé sách maith an táille Ãosta seo a Ãoc, ach bÃodh a fhios agat go bhféadfadh idirbheart nach ndeimhnÃtear riamh a bheith mar thoradh air seo a nuair a bhÃonn nÃos mó éilimh ar idirbhearta bitcoin ná mar is féidir leis an lÃonra a phróiseáil.</translation> </message> @@ -2199,6 +3044,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">D’fhéadfadh idirbheart nach ndeimhnÃtear riamh a bheith mar thoradh ar tháille ró-Ãseal (léigh an leid uirlise)</translation> </message> <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> + <translation type="unfinished">(NÃor cuireadh tús leis an táille chliste go fóill. Tógann sé seo cúpla bloc de ghnáth...)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation type="unfinished">Sprioc am dearbhaithe:</translation> </message> @@ -2255,6 +3104,20 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 (%2 bloic)</translation> </message> <message> + <source>Sign on device</source> + <extracomment>"device" usually means a hardware wallet.</extracomment> + <translation type="unfinished">SÃnigh ar an ngléas</translation> + </message> + <message> + <source>Connect your hardware wallet first.</source> + <translation type="unfinished">Ceangail do sparán crua-earraà ar dtús.</translation> + </message> + <message> + <source>Set external signer script path in Options -> Wallet</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">Socraigh cosán script sÃnitheora seachtrach i Roghanna -> Sparán</translation> + </message> + <message> <source>Cr&eate Unsigned</source> <translation type="unfinished">Cruthaigh Gan SÃn</translation> </message> @@ -2271,15 +3134,42 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">%1 go %2</translation> </message> <message> + <source>To review recipient list click "Show Details…"</source> + <translation type="unfinished">Chun liosta na bhfaighteoirà a athbhreithniú cliceáil "Taispeáin SonraÃ…"</translation> + </message> + <message> + <source>Sign failed</source> + <translation type="unfinished">Theip ar an sÃniú</translation> + </message> + <message> + <source>External signer not found</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">NÃor aimsÃodh sÃnitheoir seachtrach</translation> + </message> + <message> + <source>External signer failure</source> + <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> + <translation type="unfinished">Teip sÃnitheora sheachtraigh</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">Sábháil Sonraà Idirbheart</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">Idirbheart Páirt-SÃnithe (Dénártha)</translation> + </message> + <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> <translation type="unfinished">IBSP sábháilte</translation> </message> <message> + <source>External balance:</source> + <translation type="unfinished">Iarmhéid seachtrach:</translation> + </message> + <message> <source>or</source> <translation type="unfinished">nó</translation> </message> @@ -2293,6 +3183,20 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Le do thoil, déan athbhreithniú ar do thogra idirbhirt. Tabharfaidh sé seo Idirbheart Bitcoin SÃnithe go Páirteach (IBSP) ar féidir leat a shábháil nó a chóipeáil agus a shÃniú ansin le m.sh. sparán as lÃne %1, nó sparán crua-earraà atá comhoiriúnach le IBSP.</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 ó sparán '%2'</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">Ar mhaith leat an t-idirbheart seo a chruthú?</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">Le do thoil, athbhreithnigh d'idirbheart. Is féidir leat an t-idirbheart seo a chruthú agus a sheoladh nó Idirbheart Bitcoin Páirt-SÃnithe (PSBT) a chruthú, ar féidir leat a shábháil nó a chóipeáil agus a shÃniú ansin le, m.sh., sparán %1 as lÃne, nó sparán crua-earraà PSBT-comhoiriúnach.</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">Le do thoil, déan athbhreithniú ar d’idirbheart.</translation> @@ -2310,6 +3214,20 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Iomlán</translation> </message> <message> + <source>Unsigned Transaction</source> + <comment>PSBT copied</comment> + <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> + <translation type="unfinished">Idirbheart Gan SÃnithe</translation> + </message> + <message> + <source>The PSBT has been copied to the clipboard. You can also save it.</source> + <translation type="unfinished">Tá an PSBT cóipeáilte chuig an ngearrthaisce. Is féidir leat é a shábháil freisin.</translation> + </message> + <message> + <source>PSBT saved to disk</source> + <translation type="unfinished">PSBT sábháilte ar diosca</translation> + </message> + <message> <source>Confirm send coins</source> <translation type="unfinished">Deimhnigh seol boinn</translation> </message> @@ -2348,9 +3266,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> + <numerusform>Meastar go dtosóidh an deimhniú laistigh de %n bloc(s).</numerusform> </translation> </message> <message> @@ -2588,6 +3506,17 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> </message> </context> <context> + <name>SplashScreen</name> + <message> + <source>(press q to shutdown and continue later)</source> + <translation type="unfinished">(brúigh q chun múchadh agus lean ar aghaidh ar ball)</translation> + </message> + <message> + <source>press q to shutdown</source> + <translation type="unfinished">brúigh q chun múchadh</translation> + </message> +</context> +<context> <name>TransactionDesc</name> <message> <source>conflicted with a transaction with %1 confirmations</source> @@ -2595,6 +3524,16 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">faoi choimhlint le idirbheart le %1 dearbhuithe</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/neamhdhearbhaithe, i linn cuimhne</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/neamhdhearbhaithe, nà sa 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> @@ -2656,9 +3595,9 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> - <numerusform /> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> + <numerusform>aibÃonn i %n bloc(anna) eile</numerusform> </translation> </message> <message> @@ -2710,6 +3649,10 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Innéacs aschuir</translation> </message> <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (NÃor fÃoraÃodh an teastas)</translation> + </message> + <message> <source>Merchant</source> <translation type="unfinished">CeannaÃ</translation> </message> @@ -2895,6 +3838,55 @@ Nà féidir sÃniú ach le seoltaà 'oidhreachta'.</translation> <translation type="unfinished">Ãosmhéid</translation> </message> <message> + <source>Range…</source> + <translation type="unfinished">Raon…</translation> + </message> + <message> + <source>&Copy address</source> + <translation type="unfinished">&Cóipeáil seoladh</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Cóipeáil &lipéad</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">Cóipeáil & méid</translation> + </message> + <message> + <source>Copy transaction &ID</source> + <translation type="unfinished">Cóipeáil idirbheart &ID</translation> + </message> + <message> + <source>Copy &raw transaction</source> + <translation type="unfinished">Cóipeáil &amh-idirbheart</translation> + </message> + <message> + <source>Copy full transaction &details</source> + <translation type="unfinished">Cóipeáil idirbheart agus sonraà iomlána</translation> + </message> + <message> + <source>&Show transaction details</source> + <translation type="unfinished">&Taispeáin sonraà idirbhirt</translation> + </message> + <message> + <source>Increase transaction &fee</source> + <translation type="unfinished">Méadaigh idirbheart & táille</translation> + </message> + <message> + <source>A&bandon transaction</source> + <translation type="unfinished">Idirbheart&tréigean</translation> + </message> + <message> + <source>&Edit address label</source> + <translation type="unfinished">&Cuir lipéad seolta in eagar</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">Taispeáin i %1</translation> + </message> + <message> <source>Export Transaction History</source> <translation type="unfinished">Easpórtáil Stair Idirbheart</translation> </message> @@ -3023,6 +4015,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Táille nua:</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">Rabhadh: D’fhéadfadh sé seo an táille bhreise a Ãoc trà aschuir athraithe a laghdú nó trà ionchuir a chur leis, nuair is gá. Féadfaidh sé aschur athraithe nua a chur leis mura bhfuil ceann ann cheana. D'fhéadfadh na hathruithe seo prÃobháideacht a sceitheadh.</translation> + </message> + <message> <source>Confirm fee bump</source> <translation type="unfinished">Dearbhaigh preab táille</translation> </message> @@ -3035,6 +4031,11 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">IBSP cóipeáilte</translation> </message> <message> + <source>Copied to clipboard</source> + <comment>Fee-bump PSBT saved</comment> + <translation type="unfinished">Cóipeáladh chuig an ngearrthaisce</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Nà féidir sÃniú idirbheart.</translation> </message> @@ -3043,6 +4044,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃorbh fhéidir feidhmiú idirbheart</translation> </message> <message> + <source>Can't display address</source> + <translation type="unfinished">Nà féidir an seoladh a thaispeáint</translation> + </message> + <message> <source>default wallet</source> <translation type="unfinished">sparán réamhshocraithe</translation> </message> @@ -3062,6 +4067,11 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Sparán Chúltaca</translation> </message> <message> + <source>Wallet Data</source> + <extracomment>Name of the wallet data file format.</extracomment> + <translation type="unfinished">Sonraà Sparán</translation> + </message> + <message> <source>Backup Failed</source> <translation type="unfinished">Theip ar cúltacú</translation> </message> @@ -3093,18 +4103,86 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Tá %s truaillithe. Triail an uirlis sparán bitcoin-wallet a úsáid chun tharrtháil nó chun cúltaca a athbhunú.</translation> </message> <message> + <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> + <translation type="unfinished">Theip ar %s an staid snapshot -assumeutxo a bhailÃochtú. LéirÃonn sé seo fadhb crua-earraÃ, nó fabht sna bogearraÃ, nó droch-mhodhnú bogearraà a cheadaigh pictiúr neamhbhailà a luchtú. Mar thoradh air seo, stopfar an nód agus stopfaidh sé de úsáid a bhaint as staid ar bith a tógadh ar an seat, ag athshocrú airde an tslabhra ó%dgo%d. Ar an gcéad atosú eile, athchromfar ar an nód ag sioncronú ó %d gan úsáid a bhaint as sonraà seat. Tuairiscigh an teagmhas seo do %s lena n-áirÃtear conas a fuair tú an pictiúr. Fágfar an slabhrashlabhra neamhbhailà ar an diosca ar eagla go mbeadh sé ina chuidiú leis an tsaincheist ba chúis leis an earráid seo a dhiagnóisiú.</translation> + </message> + <message> + <source>%s request to listen on port %u. This port is considered "bad" 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">Iarraidh %s éisteacht ar phort %u. Meastar go bhfuil an port seo "olc" agus dá bhrà sin nà dócha go nascfaidh piaraà ar bith leis. Féach doc/p2p-bad-ports.md le haghaidh sonraà agus liosta iomlán.</translation> + </message> + <message> + <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> + <translation type="unfinished">Nà féidir an sparán a Ãosghrádú ó leagan %igo leagan%i. Leagan sparán gan athrú.</translation> + </message> + <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation type="unfinished">Nà féidir glas a fháil ar eolaire sonraà %s. Is dócha go bhfuil %s ag rith cheana.</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">Nà féidir sparán scoilte neamh-HD a uasghrádú ó leagan%igo leagan%i gan uasghrádú chun tacú le heochrach réamh-scoilte. Úsáid leagan %i nó nÃl aon leagan sonraithe.</translation> + </message> + <message> + <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">Nà féidir spás diosca le haghaidh %sa chur san áireamh sna blocchomhaid. Stórálfar thart ar %u GB de shonraà san eolaire seo.</translation> + </message> + <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished">Dáilte faoin gceadúnas bogearraà MIT, féach na comhad atá in éindà %s nó %s</translation> </message> <message> + <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">Earráid agus an sparán á lódáil. ÉilÃonn Sparán go n-Ãoslódálfar bloic, agus nà thacaÃonn bogearraà faoi láthair le sparán a luchtú agus bloic á n-Ãoslódáil as ord nuair a úsáidtear snapshots assumeutxo. Ba cheart go mbeadh Sparán in ann luchtú go rathúil nuair a shroicheann sioncronú nód an airde %s</translation> + </message> + <message> + <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> + <translation type="unfinished">Earráid agus %s á léamh! Seans go bhfuil sonraà idirbhirt in easnamh nó mÃcheart. Sparán athscanadh.</translation> + </message> + <message> + <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <translation type="unfinished">Earráid agus%s á léamh! Seans go bhfuil sonraà idirbhirt in easnamh nó mÃcheart. Sparán athscanadh.</translation> + </message> + <message> + <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> + <translation type="unfinished">Earráid: Tá taifead aitheantóra Dumpfile mÃcheart. Fuair ​​​​tú "%s", bhÃothas ag súil le "%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">Earráid: Nà thacaÃtear leis an leagan Dumpfile. Nà thacaÃonn an leagan seo de bitcoin-sparán ach le leagan 1 dumpfiles. Fuair ​​​​tú dumpfile le leagan %s</translation> + </message> + <message> + <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> + <translation type="unfinished">Earráid: Nà thacaÃonn sparán oidhreachta ach na cineálacha seoltaà "oidhreacht", "p2sh-segwit", agus "bech32"</translation> + </message> + <message> + <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> + <translation type="unfinished">Earráid: Nà féidir tuairisceoirà a tháirgeadh don sparán oidhreachta seo. Bà cinnte pasfhrása an sparán a sholáthar má tá sé criptithe.</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">Tá comhad %s ann cheana. Má tá tú cinnte gurb é seo a theastaÃonn uait, bog é as an mbealach ar dtú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 neamhbhailà nó truaillithe (%s). Má chreideann tú gur fabht é seo, cuir in iúl do %s é le do thoil. Mar shruth oibre, is féidir leat an comhad (%s) a bhogadh as an mbealach (athainmnigh, bog nó scrios) chun ceann nua a chruthú ar an gcéad thús eile.</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">Tá nÃos mó ná seoladh ceangail oinniún amháin curtha ar fáil. Ag baint úsáide as %s don tseirbhÃs Tor oinniún a cruthaÃodh go huathoibrÃoch.</translation> </message> <message> + <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh aon chomhad dumpála. Chun createfromdump a úsáid, nà mór -dumpfile=<filename> a sholáthar.</translation> + </message> + <message> + <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh aon chomhad dumpála. Chun Dumpáil a úsáid, nà mór -dumpfile=<filename>a sholáthar.</translation> + </message> + <message> + <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> + <translation type="unfinished">NÃor soláthraÃodh formáid comhaid sparán. Chun createfromdump a úsáid, nà mór -format=<format> a sholáthar.</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">Le do thoil seiceáil go bhfuil dáta agus am do rÃomhaire ceart! Má tá do chlog mÃcheart, nà oibreoidh %s i gceart.</translation> </message> @@ -3117,10 +4195,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Bearradh cumraithe faoi bhun an Ãosmhéid %d MiB. Úsáid uimhir nÃos airde le do thoil.</translation> </message> <message> + <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> + <translation type="unfinished">NÃl an modh prúnaà ag luà le -reindex-chainstate. Úsáid lán-reindex ina ionad sin.</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">Bearradh: téann sioncrónú deireanach an sparán thar sonraà bearrtha. Nà mór duit -reindex (déan an blockchain iomlán a Ãoslódáil arÃs i gcás nód bearrtha)</translation> </message> <message> + <source>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.</source> + <translation type="unfinished">Theip ar athainmniú '%s' -> '%s'. Ba cheart duit é seo a réiteach trÃd an gcomhadlann achomair neamhbhailà %s a bhogadh nó a scriosadh de láimh, nó beidh an earráid chéanna agat arÃs ar an gcéad tosaithe eile.</translation> + </message> + <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> <translation type="unfinished">SQLiteDatabase: Leagan scéime sparán sqlite anaithnid %d. Nà thacaÃtear ach le leagan %d</translation> </message> @@ -3161,6 +4247,30 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir bloic a aithrise. Beidh ort an bunachar sonraà a atógáil ag úsáid -reindex-chainstate.</translation> </message> <message> + <source>Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> + <translation type="unfinished">Cuireadh formáid comhaid sparán anaithnid "%s" ar fáil. Tabhair ceann de "bdb" nó "sqlite".</translation> + </message> + <message> + <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> + <translation type="unfinished">Leibhéal logála catagóir ar leith nach dtacaÃtear leis %1$s=%2$s. BhÃothas ag súil le %1$s=1:2. Catagóirà bailÃ: %3$s. Leibhéil loga bailÃ: %4$s.</translation> + </message> + <message> + <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> + <translation type="unfinished">AimsÃodh formáid bhunachar sonraà chainstáit nach dtacaÃtear léi. Atosaigh le -reindex-chainstate. Déanfaidh sé seo an bunachar sonraà slabhrach a atógáil.</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">Sparán cruthaithe go rathúil. Tá an cineál sparán oidhreachta á dhÃmheas agus bainfear an tacaÃocht chun sparán oidhreachta a chruthú agus a oscailt amach anseo.</translation> + </message> + <message> + <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> + <translation type="unfinished">D'éirigh leis an sparán a lódáil. Tá an cineál sparán oidhreachta á dhÃmheas agus bainfear an tacaÃocht chun sparán oidhreachta a chruthú agus a oscailt amach anseo. Is féidir sparán oidhreachta a aistriú chuig sparán tuairisceora le sparán imirceach.</translation> + </message> + <message> + <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <translation type="unfinished">Rabhadh: Nà mheaitseálann formáid sparán Dumpfile "%s" an fhormáid ordaithe sonraithe "%s".</translation> + </message> + <message> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation type="unfinished">Rabhadh: Eochracha prÃobháideacha braite i sparán {%s} le heochracha prÃobháideacha dÃchumasaithe</translation> </message> @@ -3169,6 +4279,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Rabhadh: Is cosúil nach n-aontaÃmid go hiomlán lenár piaraÃ! B’fhéidir go mbeidh ort uasghrádú a dhéanamh, nó b’fhéidir go mbeidh ar nóid eile uasghrádú.</translation> </message> <message> + <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> + <translation type="unfinished">TeastaÃonn bailÃochtú sonraà finné maidir le bloic tar éis airde %d. Atosaigh le -reindex le do thoil.</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">Nà mór duit an bunachar sonraà a atógáil ag baint úsáide as -reindex chun dul ar ais go mód neamhbhearrtha. Déanfaidh sé seo an blockchain iomlán a athlódáil</translation> </message> @@ -3189,6 +4303,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir réiteach seoladh -%s: '%s'</translation> </message> <message> + <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> + <translation type="unfinished">Nà féidir -forcednsseed a shocrú go fÃor agus -dnsseed á shocrú go bréagach.</translation> + </message> + <message> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> <translation type="unfinished">Nà féidir -peerblockfilters a shocrú gan -blockfilterindex.</translation> </message> @@ -3197,6 +4315,128 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir scrÃobh chuig eolaire sonraà '%s'; seiceáil ceadanna.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">Tá%s socraithe an-ard! D’fhéadfaà táillà chomh mór seo a Ãoc ar idirbheart amháin.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> + <translation type="unfinished">Nà féidir naisc ar leith a sholáthar agus tá addrman chun naisc amach a aimsiú ag an am céanna.</translation> + </message> + <message> + <source>Error loading %s: External signer wallet being loaded without external signer support compiled</source> + <translation type="unfinished">Earráid agus %s á lódáil: sparán an tsÃnitheora sheachtraigh á luchtú gan tacaÃocht sÃnitheoir seachtrach a chur le chéile</translation> + </message> + <message> + <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> + <translation type="unfinished">Earráid agus %s á léamh! Léann na heochracha go léir i gceart, ach seans go bhfuil sonraà idirbhirt nó meiteashonraà seolta in easnamh nó mÃcheart.</translation> + </message> + <message> + <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Earráid: Nà féidir sonraà an leabhair seoltaà sa sparán a shainaithint mar go mbaineann siad le sparán aistrithe</translation> + </message> + <message> + <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> + <translation type="unfinished">Earráid: Tuairisceoirà dúblacha a cruthaÃodh le linn imirce. Seans go bhfuil do sparán truaillithe.</translation> + </message> + <message> + <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished">Earráid: Nà féidir idirbheart %s sa sparán a aithint gur le sparán aistrithe é</translation> + </message> + <message> + <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> + <translation type="unfinished">Theip ar tháillà tuairte a rÃomh, toisc go mbraitheann UTXOanna neamhdhearbhaithe ar bhraisle ollmhór idirbheart neamhdheimhnithe.</translation> + </message> + <message> + <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> + <translation type="unfinished">Theip ar an gcomhad peers.dat neamhbhailà a athainmniú. Bog nó scrios é agus bain triail eile as.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">Theip ar mheastachán na dtáillÃ. Tá fallbackfee dÃchumasaithe. Fan cúpla bloc nó cumasaigh %s.</translation> + </message> + <message> + <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> + <translation type="unfinished">Roghanna neamh-chomhoiriúnacha: -dnsseed=1 sonraÃodh go sainráite, ach cuireann -onlynet cosc ​​ar naisc le IPv4/IPv6</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=<amount>: '%s' (nà mór an táille sealaÃochta nóiméad de %s a bheith ann ar a laghad chun idirbhearta bhfostú a chosc)</translation> + </message> + <message> + <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> + <translation type="unfinished">Naisc amach teoranta do CJDNS (-onlynet=cjdns) ach nà chuirtear -cjdnsreachable ar fáil</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">Tá naisc amach teoranta do Tor (-onlynet=onion) ach tá cosc ​​sainráite ar an seachfhreastalaà chun lÃonra Tor a bhaint amach: -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">Naisc amach teoranta do Tor (-onlynet=onion) ach nà thugtar an seachfhreastalaà chun lÃonra Tor a bhaint amach: nà thugtar aon seachfhreastalaÃ, -oinniún nó -listenonion</translation> + </message> + <message> + <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> + <translation type="unfinished">Tá naisc amach teoranta do i2p (-onlynet=i2p) ach nà chuirtear -i2psam ar fáil</translation> + </message> + <message> + <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> + <translation type="unfinished">SáraÃonn méid an ionchuir an t-uasmheáchan. Bain triail as méid nÃos lú a sheoladh nó UTXO do sparán a chomhdhlúthú de láimh</translation> + </message> + <message> + <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">Nà chlúdaÃonn méid iomlán na monaà réamhroghnaithe sprioc an idirbhirt. Ceadaigh le do thoil ionchuir eile a roghnú go huathoibrÃoch nó cuir nÃos mó bonn san áireamh de láimh</translation> + </message> + <message> + <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> + <translation type="unfinished">ÉilÃonn an t-idirbheart ceann scrÃbe amháin de luach neamh-0, táille neamh-0, nó ionchur réamhroghnaithe</translation> + </message> + <message> + <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> + <translation type="unfinished">Theip ar bhailÃochtú a dhéanamh ar achomair UTXO. Atosaigh chun gnáthÃoslódáil na mbloc tosaigh a atosú, nó bain triail as pictiúr eile a lódáil.</translation> + </message> + <message> + <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> + <translation type="unfinished">Tá UTXOanna neamhdheimhnithe ar fáil, ach cruthaÃtear slabhra idirbheart a ndiúltóidh an mempool dóibh má dhéantar iad a chaitheamh</translation> + </message> + <message> + <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">Fuarthas iontráil oidhreachta gan choinne sa sparán tuairisceora. Sparán %s á lódáil + +Seans gur cuireadh isteach ar an sparán nó gur cruthaÃodh é le hintinn mhailÃseach. +</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">Tuairisceoir neamhaitheanta aimsithe. Sparán %s á lódáil + +Seans gur cruthaÃodh an sparán ar leagan nÃos nuaÃ. +Bain triail as an leagan bogearraà is déanaà a rith. +</translation> + </message> + <message> + <source> +Unable to cleanup failed migration</source> + <translation type="unfinished"> +Nà féidir an t-imirce theip a ghlanadh</translation> + </message> + <message> + <source> +Unable to restore backup of wallet.</source> + <translation type="unfinished"> +Nà féidir cúltaca an sparán a chur ar ais.</translation> + </message> + <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">Cuireadh isteach ar an bhfÃorú blocála</translation> + </message> + <message> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished">Nà chuirtear socrú cumraÃochta do %s i bhfeidhm ach ar lÃonra %s nuair atá sé sa rannán [%s].</translation> </message> @@ -3229,6 +4469,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Lódáil déanta</translation> </message> <message> + <source>Dump file %s does not exist.</source> + <translation type="unfinished">NÃl an comhad dumpála %s ann.</translation> + </message> + <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Earráid agus db txn á dhéanamh chun idirbhearta sparán a bhaint</translation> + </message> + <message> + <source>Error creating %s</source> + <translation type="unfinished">Earráid cruthaithe %s</translation> + </message> + <message> <source>Error initializing block database</source> <translation type="unfinished">Earráid ag túsú bunachar sonraà bloic</translation> </message> @@ -3261,18 +4513,114 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Earráid ag oscailt bunachar sonraà bloic</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">Earráid agus an comhad cumraÃochta á léamh: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">Earráid ag léamh ón mbunachar sonraÃ, ag múchadh.</translation> </message> <message> + <source>Error reading next record from wallet database</source> + <translation type="unfinished">Earráid agus an chéad taifead eile á léamh ón mbunachar sonraà sparán</translation> + </message> + <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Earráid agus db txn á thosú chun idirbhearta sparán a bhaint</translation> + </message> + <message> + <source>Error: Cannot extract destination from the generated scriptpubkey</source> + <translation type="unfinished">Earráid: Nà féidir an ceann scrÃbe a bhaint as an scriptpubkey ginte</translation> + </message> + <message> + <source>Error: Couldn't create cursor into database</source> + <translation type="unfinished">Earráid: NÃorbh fhéidir an cúrsóir a chruthú sa bhunachar sonraÃ</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> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">Earráid: Nà hionann seiceála Dumpfile. RÃomh %s, bhÃothas ag súil le %s</translation> + </message> + <message> + <source>Error: Failed to create new watchonly wallet</source> + <translation type="unfinished">Earráid: Theip ar chruthú sparán faire amháin nua</translation> + </message> + <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">Earráid: Fuair ​​​​tú eochair nach heicsidheachúlach Ã: %s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">Earráid: Fuair ​​tú luach nach heicsidheachúlach é: %s</translation> + </message> + <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> <translation type="unfinished">Earráid: Rith keypool amach, glaoigh ar keypoolrefill ar dtús</translation> </message> <message> + <source>Error: Missing checksum</source> + <translation type="unfinished">Earráid: Seiceáil in easnamh</translation> + </message> + <message> + <source>Error: No %s addresses available.</source> + <translation type="unfinished">Earráid: NÃl seoladh %s ar fáil.</translation> + </message> + <message> + <source>Error: This wallet already uses SQLite</source> + <translation type="unfinished">Earráid: Úsáideann an sparán seo SQLite cheana féin</translation> + </message> + <message> + <source>Error: This wallet is already a descriptor wallet</source> + <translation type="unfinished">Earráid: Is sparán tuairisceora é an sparán seo cheana féin</translation> + </message> + <message> + <source>Error: Unable to begin reading all records in the database</source> + <translation type="unfinished">Earráid: Nà féidir tosú ag léamh gach taifead sa bhunachar sonraÃ</translation> + </message> + <message> + <source>Error: Unable to make a backup of your wallet</source> + <translation type="unfinished">Earráid: Nà féidir cúltaca a dhéanamh de do sparán</translation> + </message> + <message> + <source>Error: Unable to parse version %u as a uint32_t</source> + <translation type="unfinished">Earráid: Nà féidir leagan%u a pharsáil mar uint32_t</translation> + </message> + <message> + <source>Error: Unable to read all records in the database</source> + <translation type="unfinished">Earráid: Nà féidir gach taifead sa bhunachar sonraà a léamh</translation> + </message> + <message> + <source>Error: Unable to read wallet's best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr sa sparán a léamh</translation> + </message> + <message> + <source>Error: Unable to remove watchonly address book data</source> + <translation type="unfinished">Earráid: Nà féidir sonraà leabhar seoltaà faire amháin a bhaint</translation> + </message> + <message> + <source>Error: Unable to write record to new wallet</source> + <translation type="unfinished">Earráid: Nà féidir taifead a scrÃobh chuig an sparán nua</translation> + </message> + <message> + <source>Error: Unable to write solvable wallet best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr ar an sparán intuaslagtha a scrÃobh</translation> + </message> + <message> + <source>Error: Unable to write watchonly wallet best block locator record</source> + <translation type="unfinished">Earráid: Nà féidir an taifead aimsitheoir bloc is fearr le sparán faire amháin a scrÃobh</translation> + </message> + <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Earráid: theip ar chóip leabhar seoltaà do sparán %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Earráid: nà féidir idirbheart bunachar sonraà a chur i gcrÃch le haghaidh sparán %s</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Theip ar éisteacht ar aon phort. Úsáid -listen=0 más é seo atá uait.</translation> </message> @@ -3281,10 +4629,18 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Theip athscanadh ar an sparán le linn túsúchán</translation> </message> <message> + <source>Failed to start indexes, shutting down..</source> + <translation type="unfinished">Theip ar thús a chur leis na hinnéacsanna, dúnadh.</translation> + </message> + <message> <source>Failed to verify database</source> <translation type="unfinished">Theip ar fhÃorú an mbunachar sonraÃ</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Teip ag baint an idirbhirt: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">Tá an ráta táillà (%s) nÃos Ãsle ná an socrú Ãosta rátaà táille (%s).</translation> </message> @@ -3293,6 +4649,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Neamhaird ar sparán dhúbailt %s.</translation> </message> <message> + <source>Importing…</source> + <translation type="unfinished">à iompórtáil…</translation> + </message> + <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> <translation type="unfinished">Bloc geineasas mÃcheart nó nà aimsithe. datadir mÃcheart don lÃonra?</translation> </message> @@ -3301,10 +4661,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Theip ar seiceáil slánchiall túsúchán. Tá %s ag múchadh.</translation> </message> <message> + <source>Input not found or already spent</source> + <translation type="unfinished">Ionchur gan aimsiú nó caite cheana féin</translation> + </message> + <message> + <source>Insufficient dbcache for block verification</source> + <translation type="unfinished">Dbcache neamhleor le haghaidh fÃorú blocála</translation> + </message> + <message> <source>Insufficient funds</source> <translation type="unfinished">Neamhleor ciste</translation> </message> <message> + <source>Invalid -i2psam address or hostname: '%s'</source> + <translation type="unfinished">Seoladh neamhbhailà -i2psam nó óstainm: '%s'</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation type="unfinished">Seoladh neamhbhailà -onion nó óstainm: '%s'</translation> </message> @@ -3317,6 +4689,14 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Cead neamhbhailà P2P: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=<amount>: '%s' (ar a laghad %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Méid neamhbhailà le haghaidh %s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">Suim neamhbhailà do -%s=<amount>: '%s'</translation> </message> @@ -3325,14 +4705,62 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Mascghréas neamhbhailà sonraithe sa geal-liosta: '%s'</translation> </message> <message> + <source>Invalid port specified in %s: '%s'</source> + <translation type="unfinished">Port neamhbhailà sonraithe i %s: '%s'</translation> + </message> + <message> + <source>Invalid pre-selected input %s</source> + <translation type="unfinished">Ionchur réamhroghnaithe %s neamhbhailÃ</translation> + </message> + <message> + <source>Listening for incoming connections failed (listen returned error %s)</source> + <translation type="unfinished">Theip ar éisteacht le naisc isteach (éisteacht ar ais earráid %s)</translation> + </message> + <message> + <source>Loading P2P addresses…</source> + <translation type="unfinished">Seoltaà P2P á lódáil…</translation> + </message> + <message> + <source>Loading banlist…</source> + <translation type="unfinished">Liosta toirmeasc á lódáil…</translation> + </message> + <message> + <source>Loading block index…</source> + <translation type="unfinished">Innéacs bloc á lódáil…</translation> + </message> + <message> + <source>Loading wallet…</source> + <translation type="unfinished">Sparán á lódáil…</translation> + </message> + <message> + <source>Missing amount</source> + <translation type="unfinished">Méid ar iarraidh</translation> + </message> + <message> + <source>Missing solving data for estimating transaction size</source> + <translation type="unfinished">Sonraà réitigh ar iarraidh le haghaidh meastachán a dhéanamh ar mhéid an idirbhirt</translation> + </message> + <message> <source>Need to specify a port with -whitebind: '%s'</source> <translation type="unfinished">Is gá port a shainiú le -whitebind: '%s'</translation> </message> <message> + <source>No addresses available</source> + <translation type="unfinished">NÃl aon seoltaà ar fáil</translation> + </message> + <message> <source>Not enough file descriptors available.</source> <translation type="unfinished">NÃl dóthain tuairisceoirà comhaid ar fáil.</translation> </message> <message> + <source>Not found pre-selected input %s</source> + <translation type="unfinished">NÃor aimsÃodh ionchur réamhroghnaithe %s</translation> + </message> + <message> + <source>Not solvable pre-selected input %s</source> + <translation type="unfinished">Nà féidir ionchur réamhroghnaithe %s a réiteach</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Nà féidir Bearradh a bheidh cumraithe le luach diúltach.</translation> </message> @@ -3341,10 +4769,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Tá an mód bearrtha neamh-chomhoiriúnach le -txindex.</translation> </message> <message> + <source>Pruning blockstore…</source> + <translation type="unfinished">Blocsiopa á bhearradh…</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation type="unfinished">Laghdú -maxconnections ó %d go %d, mar gheall ar shrianadh an chórais.</translation> </message> <message> + <source>Replaying blocks…</source> + <translation type="unfinished">Bloic á n-athsheinn…</translation> + </message> + <message> + <source>Rescanning…</source> + <translation type="unfinished">à athscanadh…</translation> + </message> + <message> <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> <translation type="unfinished">SQLiteDatabase: Theip ar rith ráiteas chun an bunachar sonraà a fhÃorú: %s</translation> </message> @@ -3385,10 +4825,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃl eolaire bloic shonraithe "%s" ann.</translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">NÃl comhadlann sonraà sonraithe "%s" ann.</translation> + </message> + <message> + <source>Starting network threads…</source> + <translation type="unfinished">Snáitheanna lÃonra á dtosú…</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation type="unfinished">Tá an cód foinseach ar fáil ó %s.</translation> </message> <message> + <source>The specified config file %s does not exist</source> + <translation type="unfinished">NÃl an comhad cumraÃochta sonraithe %s ann</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation type="unfinished">Tá suim an idirbhirt ró-bheag chun an táille a Ãoc</translation> </message> @@ -3409,6 +4861,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Seo an táille idirbhirt a Ãocfaidh tú má sheolann tú idirbheart.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Nà bhaineann an t-idirbheart %s leis an sparán seo</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Méid an idirbhirt ró-bheag</translation> </message> @@ -3417,14 +4873,26 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃor cheart go mbeadh suimeanna idirbhirt diúltach</translation> </message> <message> + <source>Transaction change output index out of range</source> + <translation type="unfinished">Innéacs aschuir athraithe idirbhirt as raon</translation> + </message> + <message> <source>Transaction must have at least one recipient</source> <translation type="unfinished">Caithfidh ar a laghad faighteoir amháin a bheith ag idirbheart</translation> </message> <message> + <source>Transaction needs a change address, but we can't generate it.</source> + <translation type="unfinished">TeastaÃonn seoladh athraithe ón idirbheart, ach nà féidir linn é a ghiniúint.</translation> + </message> + <message> <source>Transaction too large</source> <translation type="unfinished">Idirbheart ró-mhór</translation> </message> <message> + <source>Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> + <translation type="unfinished">Nà féidir cuimhne a leithdháileadh le haghaidh -maxsigcachesize: '%s' MiB</translation> + </message> + <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> <translation type="unfinished">Nà féidir ceangal le %s ar an rÃomhaire seo (thug ceangail earráid %s ar ais)</translation> </message> @@ -3437,6 +4905,10 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">NÃorbh fhéidir cruthú comhad PID '%s': %s</translation> </message> <message> + <source>Unable to find UTXO for external input</source> + <translation type="unfinished">Nà féidir UTXO a aimsiú le haghaidh ionchur seachtrach</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation type="unfinished">Nà féidir eochracha tosaigh a ghiniúint</translation> </message> @@ -3445,10 +4917,22 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">Nà féidir eochracha a ghiniúint</translation> </message> <message> + <source>Unable to open %s for writing</source> + <translation type="unfinished">Nà féidir %s a oscailt chun scrÃobh</translation> + </message> + <message> + <source>Unable to parse -maxuploadtarget: '%s'</source> + <translation type="unfinished">Nà féidir a pharsáil -maxuploadtarget: '%s'</translation> + </message> + <message> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished">Nà féidir freastalaà HTTP a thosú. Féach loga dÃfhabhtúcháin le tuilleadh sonraÃ.</translation> </message> <message> + <source>Unable to unload the wallet before migrating</source> + <translation type="unfinished">Nà féidir an sparán a dhÃluchtú roimh aistriú</translation> + </message> + <message> <source>Unknown -blockfilterindex value %s.</source> <translation type="unfinished">Luach -blockfilterindex %s anaithnid.</translation> </message> @@ -3465,16 +4949,56 @@ Téigh go Comhad > Oscail Sparán chun sparán a lódáil. <translation type="unfinished">LÃonra anaithnid sonraithe san -onlynet: '%s'</translation> </message> <message> + <source>Unknown new rules activated (versionbit %i)</source> + <translation type="unfinished">Rialacha nua anaithnid curtha i ngnÃomh (leagan giotán %ii)</translation> + </message> + <message> + <source>Unsupported global logging level %s=%s. Valid values: %s.</source> + <translation type="unfinished">Leibhéal logála domhanda nach dtacaÃtear leis %s=%s. Luachanna bailÃ: %s.</translation> + </message> + <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Theip ar chruthú comhaid sparán: %s</translation> + </message> + <message> + <source>acceptstalefeeestimates is not supported on %s chain.</source> + <translation type="unfinished">nà thacaÃtear le acceptstalefeeestimates ar slabhra %s.</translation> + </message> + <message> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished">Catagóir logáil gan tacaÃocht %s=%s.</translation> </message> <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">Earráid: NÃorbh fhéidir watch amháin tx %s a chur le sparán faire amháin</translation> + </message> + <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Earráid: NÃorbh fhéidir idirbhearta faire amháin a scriosadh.</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> <message> + <source>Verifying blocks…</source> + <translation type="unfinished">Bloic á bhfÃorú…</translation> + </message> + <message> + <source>Verifying wallet(s)…</source> + <translation type="unfinished">Sparán(aÃ) á fhÃorú…</translation> + </message> + <message> <source>Wallet needed to be rewritten: restart %s to complete</source> <translation type="unfinished">Ba ghá an sparán a athscrÃobh: atosaigh %s chun crÃochnú</translation> </message> - </context> + <message> + <source>Settings file could not be read</source> + <translation type="unfinished">NÃorbh fhéidir an comhad socruithe a léamh</translation> + </message> + <message> + <source>Settings file could not be written</source> + <translation type="unfinished">NÃorbh fhéidir an comhad socruithe a scrÃobh</translation> + </message> +</context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts index df9362d664..03319ecabf 100644 --- a/src/qt/locale/bitcoin_gl.ts +++ b/src/qt/locale/bitcoin_gl.ts @@ -84,11 +84,24 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Exportar Lista de Enderezos</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">Ficheiro 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">Houbo un erro tentando gardar a lista de enderezos en %1. Por favor proba de novo.</translation> </message> <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">Enviando enderezos - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Recibindo enderezos - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Exportación falida</translation> </message> @@ -211,10 +224,22 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">O contrasinal introducido para a desencriptación do moedeiro foi incorrecto.</translation> </message> <message> + <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">A frase de acceso introducida para o descifrado da carteira é incorrecta. Contén un carácter nulo (é dicir, un byte cero). Se a frase de paso se estableceu cunha versión deste software anterior á 25.0, téntao de novo con só os caracteres ata, pero sen incluÃr, o primeiro carácter nulo. Se se realiza correctamente, establece unha nova frase de acceso para evitar este problema no futuro.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">Cambiouse con éxito o contrasinal do moedeiro.</translation> </message> <message> + <source>Passphrase change failed</source> + <translation type="unfinished">Produciuse un erro no cambio de frase de contrasinal</translation> + </message> + <message> + <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">A contrasinal antiga introducida para o descifrado da carteira é incorrecta. Contén un carácter nulo (é dicir, un byte cero). Se a frase de paso se estableceu cunha versión deste software anterior á 25.0, téntao de novo con só os caracteres ata, pero sen incluÃr, o primeiro carácter nulo.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Aviso: O Bloqueo de Maiúsculas está activo!</translation> </message> @@ -233,13 +258,33 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <context> <name>BitcoinApplication</name> <message> + <source>Settings file %1 might be corrupt or invalid.</source> + <translation type="unfinished">O ficheiro de configuración %1 pode estar danado ou non válido.</translation> + </message> + <message> + <source>Runaway exception</source> + <translation type="unfinished">Excepción de fuga</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation type="unfinished">Produciuse un erro fatal. %1 xa non pode continuar con seguridade e sairá.</translation> + </message> + <message> <source>Internal error</source> <translation type="unfinished">Erro 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">Produciuse un erro interno. %1 tentará continuar con seguridade. Este é un erro inesperado que se pode informar como se describe a continuación.</translation> + </message> +</context> <context> <name>QObject</name> <message> + <source>%1 didn't yet exit safely…</source> + <translation type="unfinished">%1 aÃnda non saÃu con seguridade...</translation> + </message> + <message> <source>unknown</source> <translation type="unfinished">descoñecido</translation> </message> @@ -382,10 +427,22 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">&Opcións...</translation> </message> <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Cifrar carteira...</translation> + </message> + <message> <source>Encrypt the private keys that belong to your wallet</source> <translation type="unfinished">Encriptar as claves privadas que pertencen ao teu moedeiro</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Copia de seguranza da carteira...</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&Cambiar a frase de contrasinal...</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> <translation type="unfinished">Asina mensaxes cos teus enderezos Bitcoin para probar que che pertencen</translation> </message> @@ -1876,6 +1933,11 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Exportar Historial de Transaccións</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">Ficheiro separado por comas</translation> + </message> + <message> <source>Confirmed</source> <translation type="unfinished">Confirmado</translation> </message> diff --git a/src/qt/locale/bitcoin_gl_ES.ts b/src/qt/locale/bitcoin_gl_ES.ts index 854aebfc6f..a6c022038d 100644 --- a/src/qt/locale/bitcoin_gl_ES.ts +++ b/src/qt/locale/bitcoin_gl_ES.ts @@ -84,6 +84,11 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">Exporta a Lista de Enderezos</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">Ficheiro 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">Houbo un erro tentando gardar a lista de enderezos en %1. Por favor proba de novo.</translation> @@ -207,10 +212,22 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">A frase contrasinal introducida para o desencriptamento da carteira é incorrecto.</translation> </message> <message> + <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">A frase de acceso introducida para o descifrado da carteira é incorrecta. Contén un carácter nulo (é dicir, un byte cero). Se a frase de paso se estableceu cunha versión deste software anterior á 25.0, téntao de novo con só os caracteres ata, pero sen incluÃr, o primeiro carácter nulo. Se se realiza correctamente, establece unha nova frase de acceso para evitar este problema no futuro.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">A frase contrasinal da carteira mudouse correctamente.</translation> </message> <message> + <source>Passphrase change failed</source> + <translation type="unfinished">Produciuse un erro no cambio de frase de contrasinal</translation> + </message> + <message> + <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">Produciuse un erro non cambio de frase de contrasinal</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Aviso: ¡A tecla Bloq. Mayús está activada!</translation> </message> @@ -229,10 +246,22 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <context> <name>BitcoinApplication</name> <message> + <source>Runaway exception</source> + <translation type="unfinished">Excepción de fuga</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation type="unfinished">Produciuse un erro fatal. %1 xa non pode continuar con seguridade e sairá.</translation> + </message> + <message> <source>Internal error</source> <translation type="unfinished">Erro 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">Produciuse un erro interno. %1 tentará continuar con seguridade. Este é un erro inesperado que se pode informar como se describe a continuación.</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -374,10 +403,22 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">&Opcións...</translation> </message> <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&Cifrar carteira...</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> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&Copia de seguranza da carteira...</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&Cambiar a frase de contrasinal...</translation> + </message> + <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> <translation type="unfinished">Asina mensaxes cos teus enderezos de Bitcoin para probar que che pertencen</translation> </message> @@ -1061,6 +1102,11 @@ Firmar é posible unicamente con enderezos de tipo 'legacy'.</translation> <translation type="unfinished">&Copiar enderezo</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">Ficheiro separado por comas</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 54f2cd1741..6bf04dc5d1 100644 --- a/src/qt/locale/bitcoin_gu.ts +++ b/src/qt/locale/bitcoin_gu.ts @@ -94,6 +94,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">સરનામાં સૂચિને માં સાચવવાનો પà«àª°àª¯àª¾àª¸ કરતી વખતે àªà«‚લ આવી હતી %1. મહેરબાની કરીને ફરીથી પà«àª°àª¯àª¤àª¨ કરો.</translation> </message> <message> + <source>Sending addresses - %1</source> + <translation type="unfinished">મોકલવાના સરનામા - %1</translation> + </message> + <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">સરનામૠલેવà«-%1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">નિકાસ ની પà«àª°à«àª°àª¾àª•à«àª°àª¿àª¯àª¾ નિષà«àª«àª³ ગયેલ છે</translation> </message> @@ -168,21 +176,159 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">પાકીટ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ થયેલ</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation type="unfinished">વૉલેટ માટે નવો પાસફà«àª°à«‡àª દાખલ કરો. 1 કૃપા કરીને 2 દસ અથવા વધૠઅજાનà«àª¯àª¾ અકà«àª·àª°à«‹ 2 અથવા 3 આઠઅથવા વધૠશબà«àª¦à«‹àª¨àª¾ પાસફà«àª°à«‡àªàª¨à«‹ ઉપયોગ કરો 3 .</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> - </context> + <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>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">વૉલેટ ડિકà«àª°àª¿àªªà«àª¶àª¨ માટે દાખલ કરેલ પાસફà«àª°à«‡àª ખોટો છે. તેમાં નલ અકà«àª·àª° (àªàªŸàª²à«‡ ​​કે - શૂનà«àª¯ બાઈટ) છે. જો પાસફà«àª°à«‡àª 25.0 પહેલા આ સૉફà«àªŸàªµà«‡àª°àª¨àª¾ સંસà«àª•àª°àª£ સાથે સેટ કરવામાં આવà«àª¯à«‹ હોય, તો કૃપા કરીને ફકà«àª¤ પà«àª°àª¥àª® શૂનà«àª¯ અકà«àª·àª° સà«àª§à«€àª¨àª¾ અકà«àª·àª°à«‹ સાથે ફરી પà«àª°àª¯àª¾àª¸ કરો — પરંતૠતેમાં શામેલ નથી. જો આ સફળ થાય, તો àªàªµàª¿àª·à«àª¯àª®àª¾àª‚ આ સમસà«àª¯àª¾àª¨à«‡ ટાળવા માટે કૃપા કરીને નવો પાસફà«àª°à«‡àª સેટ કરો.</translation> + </message> + <message> + <source>Passphrase change failed</source> + <translation type="unfinished">પાસફà«àª°à«‡àª ફેરફાર નિષà«àª«àª³ ગયો</translation> + </message> + <message> + <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">વૉલેટ ડિકà«àª°àª¿àªªà«àª¶àª¨ માટે દાખલ કરેલ જૂનો પાસફà«àª°à«‡àª ખોટો છે. તેમાં નલ અકà«àª·àª° (àªàªŸàª²à«‡ ​​કે - શૂનà«àª¯ બાઈટ) છે. જો પાસફà«àª°à«‡àª 25.0 પહેલા આ સૉફà«àªŸàªµà«‡àª°àª¨àª¾ સંસà«àª•àª°àª£ સાથે સેટ કરવામાં આવà«àª¯à«‹ હોય, તો કૃપા કરીને ફકà«àª¤ પà«àª°àª¥àª® શૂનà«àª¯ અકà«àª·àª° સà«àª§à«€àª¨àª¾ અકà«àª·àª°à«‹ સાથે ફરી પà«àª°àª¯àª¾àª¸ કરો — પરંતૠતેમાં શામેલ નથી.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation type="unfinished">ચેતવણી: ( Caps Lock ) કી ચાલૠછે!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation type="unfinished">આઈપી/નેટમાસà«àª• </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: %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>Embedded "%1"</source> + <translation type="unfinished">àªàª®à«àª¬à«‡àª¡à«‡àª¡ "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">ડિફૉલà«àªŸ સિસà«àªŸàª® ફોનà«àªŸ "%1"</translation> + </message> + <message> + <source>Custom…</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">Bitcoin સરનામà«àª‚ દાખલ કરો (દા.ત. %1 )</translation> + </message> + <message> + <source>Unroutable</source> + <translation type="unfinished">રૂટ કરી શકાતો નથી</translation> + </message> + <message> + <source>Onion</source> + <comment>network name</comment> + <extracomment>Name of Tor network in peer info</extracomment> + <translation type="unfinished">Onion (ડà«àª‚ગળી)</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> @@ -192,25 +338,58 @@ Signing is only possible with addresses of the type 'legacy'.</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>1%n સેકનà«àª¡</numerusform> + <numerusform>%n સેકનà«àª¡à«‹</numerusform> </translation> </message> <message numerus="yes"> <source>%n minute(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>1%n મિનિટ</numerusform> + <numerusform>1%n મિનિટો</numerusform> </translation> </message> <message numerus="yes"> <source>%n hour(s)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>1%n કલાક</numerusform> + <numerusform>%n કલાકો</numerusform> </translation> </message> <message numerus="yes"> @@ -238,68 +417,998 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BitcoinGUI</name> <message> + <source>&Overview</source> + <translation type="unfinished">&àªàª¾àª‚ખી</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation type="unfinished">વૉલેટની સામાનà«àª¯ àªàª¾àª‚ખી બતાવો</translation> + </message> + <message> + <source>&Transactions</source> + <translation type="unfinished">&વà«àª¯àªµàª¹àª¾àª°à«‹</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation type="unfinished">વà«àª¯àªµàª¹àª¾àª° ઇતિહાસ બà«àª°àª¾àª‰àª કરો</translation> + </message> + <message> + <source>E&xit</source> + <translation type="unfinished">બહાર નીકળો</translation> + </message> + <message> + <source>Quit application</source> + <translation type="unfinished">àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ છોડો</translation> + </message> + <message> + <source>&About %1</source> + <translation type="unfinished">&વિશે %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation type="unfinished">વિશે માહિતી બતાવો %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation type="unfinished">&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>&Minimize</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>Proxy is <b>enabled</b>: %1</source> + <translation type="unfinished">પà«àª°à«‹àª•à«àª¸à«€ <b>સકà«àª·àª® છે </b> : %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>&Send</source> + <translation type="unfinished">&મોકલો</translation> + </message> + <message> + <source>&Receive</source> + <translation type="unfinished">&પà«àª°àª¾àªªà«àª¤ કરો</translation> + </message> + <message> + <source>&Options…</source> + <translation type="unfinished">&વિકલà«àªªà«‹...</translation> + </message> + <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">&વોલેટ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરો...</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation type="unfinished">તમારા વૉલેટની ખાનગી કીને àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરો</translation> + </message> + <message> + <source>&Backup Wallet…</source> + <translation type="unfinished">&બેકઅપ વૉલેટ...</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">&પાસફà«àª°à«‡àª &બદલો...</translation> + </message> + <message> + <source>Sign &message…</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 message…</source> + <translation type="unfinished">&સંદેશ ચકાસો...</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation type="unfinished">સંદેશાઓની ખાતરી કરવા માટે કે તેઓ નિરà«àª¦àª¿àª·à«àªŸ Bitcoin સરનામાંઓ સાથે સહી કરેલ છે તેની ખાતરી કરો</translation> + </message> + <message> + <source>&Load PSBT from file…</source> + <translation type="unfinished">&ફાઇલમાંથી PSBT લોડ કરો...</translation> + </message> + <message> + <source>Open &URI…</source> + <translation type="unfinished">ખોલો&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>&File</source> + <translation type="unfinished">&ફાઇલ</translation> + </message> + <message> + <source>&Settings</source> + <translation type="unfinished">&સેટિંગà«àª¸</translation> + </message> + <message> + <source>&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>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>&Command-line options</source> + <translation type="unfinished">&કમાનà«àª¡-લાઇન વિકલà«àªªà«‹</translation> + </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>ટà«àª°àª¾àª¨à«àªà«‡àª•à«àª¶àª¨ ઇતિહાસના પà«àª°à«‹àª¸à«‡àª¸à«àª¡ 1%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> + <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 PSBT from &clipboard…</source> + <translation type="unfinished">&કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡ માંથી 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>&Sending addresses</source> + <translation type="unfinished">&સરનામાં મોકલી રહà«àª¯àª¾àª‚ છીàª</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation type="unfinished">&પà«àª°àª¾àªªà«àª¤ સરનામાં</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>Migrate Wallet</source> + <translation type="unfinished">વૉલેટ સà«àª¥àª¾àª¨àª¾àª‚તરિત કરો</translation> + </message> + <message> + <source>Migrate a wallet</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>&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 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>&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> + <source>&Hide</source> + <translation type="unfinished">&છà«àªªàª¾àªµà«‹</translation> + </message> + <message> + <source>S&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 /> + <numerusform>1%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 creating wallet</source> + <translation type="unfinished">વૉલેટ બનાવવામાં àªà«‚લ</translation> + </message> + <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">નવà«àª‚ વૉલેટ બનાવી શકાતà«àª‚ નથી, સૉફà«àªŸàªµà«‡àª° sqlite સપોરà«àªŸ વિના સંકલિત કરવામાં આવà«àª¯à«àª‚ હતà«àª‚ (વરà«àª£àª¨àª•àª°à«àª¤àª¾ વૉલેટ માટે જરૂરી)</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 <b>enabled</b></source> + <translation type="unfinished">HD ચાવી જનરેશન <b>સકà«àª·àª®</b> કરેલ છે</translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation type="unfinished">HD કી જનરેશન <b>અકà«àª·àª®</b> છે</translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation type="unfinished">ખાનગી કી <b>અકà«àª·àª®</b> છે</translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation type="unfinished">વૉલેટ <b>àªàª¨à«àª•à«àª°àª¿àªªà«àªŸà«‡àª¡</b> છે અને હાલમાં <b>અનલૉક</b> કરેલà«àª‚ છે</translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation type="unfinished">વૉલેટ <b>àªàª¨à«àª•à«àª°àª¿àªªà«àªŸà«‡àª¡</b> છે અને હાલમાં <b>લૉક</b> કરેલà«àª‚ છે</translation> + </message> + <message> + <source>Original message:</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>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">બધા (na)પસંદ કરો</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>&Copy address</source> + <translation type="unfinished">સરનામà«àª‚ &નકલ કરો</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">કૉપિ કરો &લેબલ બનાવો</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">નકલ &રકમ</translation> + </message> + <message> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">ટà«àª°àª¾àª¨à«àªà«‡àª•à«àª¶àª¨ &ID અને આઉટપà«àªŸ ઇનà«àª¡à«‡àª•à«àª¸àª¨à«€ નકલ કરો</translation> + </message> + <message> + <source>L&ock unspent</source> + <translation type="unfinished">બિનખરà«àªšàª¿àª¤ લો&ક</translation> + </message> + <message> + <source>&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 change</source> + <translation type="unfinished">ફેરફારની નકલ કરો</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation type="unfinished">(%1લોક કરેલ)</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 <b>%1</b>…</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">વૉલેટ બનાવી રહà«àª¯àª¾àª‚ છીàª<b>%1</b>...</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>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">વૉલેટ સà«àª¥àª¾àª¨àª¾àª‚તરિત કરો</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">શà«àª‚ તમે ખરેખર વૉલેટને સà«àª¥àª¾àª¨àª¾àª‚તરિત કરવા માંગો છો<i>%1</i>?</translation> + </message> + <message> + <source>Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made. +If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts. +If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. + +The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> + <translation type="unfinished">વૉલેટનà«àª‚ સà«àª¥àª¾àª¨àª¾àª‚તરણ આ વૉલેટને àªàª• અથવા વધૠવરà«àª£àª¨àª•àª°à«àª¤àª¾ વૉલેટમાં રૂપાંતરિત કરશે. નવà«àª‚ વૉલેટ બેકઅપ લેવાની જરૂર પડશે. +જો આ વૉલેટમાં કોઈ માતà«àª° વૉચનલી સà«àª•à«àª°àª¿àªªà«àªŸà«àª¸ હોય, તો àªàª• નવà«àª‚ વૉલેટ બનાવવામાં આવશે જેમાં તે માતà«àª° વૉચનલી સà«àª•à«àª°àª¿àªªà«àªŸà«àª¸ હશે. +જો આ વૉલેટમાં કોઈ ઉકેલી શકાય તેવી પરંતૠજોઈ ન હોય તેવી સà«àª•à«àª°àª¿àªªà«àªŸà«‹ હોય, તો àªàª• અલગ અને નવà«àª‚ વૉલેટ બનાવવામાં આવશે જેમાં તે સà«àª•à«àª°àª¿àªªà«àªŸà«‹ હશે. + +સà«àª¥àª³àª¾àª‚તર પà«àª°àª•à«àª°àª¿àª¯àª¾ સà«àª¥àª³àª¾àª‚તર કરતા પહેલા વૉલેટનો બેકઅપ બનાવશે. આ બેકઅપ ફાઇલને <wallet name>-<timestamp>.legacy.bak નામ આપવામાં આવશે અને આ વૉલેટ માટેની ડિરેકà«àªŸàª°à«€àª®àª¾àª‚ મળી શકશે. અયોગà«àª¯ સà«àª¥àª¾àª¨àª¾àª‚તરણની ઘટનામાં, બેકઅપને "રીસà«àªŸà«‹àª° વોલેટ" કારà«àª¯àª•à«àª·àª®àª¤àª¾ સાથે પà«àª¨àªƒàª¸à«àª¥àª¾àªªàª¿àª¤ કરી શકાય છે.</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">વૉલેટ સà«àª¥àª¾àª¨àª¾àª‚તરિત કરો</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">વૉલેટ સà«àª¥àª¾àª¨àª¾àª‚તરિત કરી રહà«àª¯àª¾àª‚ છીàª<b>%1</b>…</translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">વૉલેટ '%1' સફળતાપૂરà«àªµàª• સà«àª¥àª¾àª¨àª¾àª‚તરિત થયà«àª‚.</translation> + </message> + <message> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">વોચઓનલી સà«àª•à«àª°àª¿àªªà«àªŸà«‹àª¨à«‡ '%1' નામના નવા વૉલેટમાં સà«àª¥àª¾àª¨àª¾àª‚તરિત કરવામાં આવી છે.</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">ઉકેલી શકાય તેવી પરંતૠજોયેલી સà«àª•à«àª°àª¿àªªà«àªŸà«‹ '%1' નામના નવા વૉલેટમાં સà«àª¥àª¾àª¨àª¾àª‚તરિત કરવામાં આવી છે.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">સà«àª¥àª³àª¾àª‚તર નિષà«àª«àª³ થયà«àª‚</translation> + </message> + <message> + <source>Migration Successful</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> + <message> + <source>Opening Wallet <b>%1</b>…</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">વૉલેટ ખોલી રહà«àª¯àª¾àª‚ છીઠ<b>%1</b>...</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 <b>%1</b>…</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">વૉલેટ પà«àª¨àªƒàª¸à«àª¥àª¾àªªàª¿àª¤ કરી રહà«àª¯àª¾àª‚ છીઠ<b>%1</b>...</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 <i>%1</i>?</source> + <translation type="unfinished">શà«àª‚ તમે ખરેખર વોલેટ બંધ કરવા માંગો છો <i>%1</i>?</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>You are one step away from creating your new wallet!</source> + <translation type="unfinished">તમે તમારà«àª‚ નવà«àª‚ વૉલેટ બનાવવાથી àªàª• પગલà«àª‚ દૂર છો!</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</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 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 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>&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>&Address</source> + <translation type="unfinished">&સરનામà«àª‚</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 /> - <numerusform /> + <numerusform>1%n GB ની જગà«àª¯àª¾ ઉપલબà«àª§ છે</numerusform> + <numerusform>%n GB ની જગà«àª¯àª¾ ઉપલબà«àª§ છે</numerusform> </translation> </message> <message numerus="yes"> <source>(of %n GB needed)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>(1%n GB ની જરૂર છે)</numerusform> + <numerusform>(%n GB ની જરૂર છે)</numerusform> </translation> </message> <message numerus="yes"> <source>(%n GB needed for full chain)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>(સંપૂરà«àª£ સાંકળ માટે 1%n GB જરૂરી છે)</numerusform> + <numerusform>(સંપૂરà«àª£ સાંકળ માટે %n GB જરૂરી છે)</numerusform> </translation> </message> + <message> + <source>Choose data directory</source> + <translation type="unfinished">ડેટા ડિરેકà«àªŸàª°à«€ પસંદ કરો</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>(બૅકઅપ 1%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> + <message> <source>Welcome</source> <translation type="unfinished">સà«àªµàª¾àª—ત છે</translation> </message> @@ -307,27 +1416,777 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Welcome to %1.</source> <translation type="unfinished">સà«àªµàª¾àª—ત છે %1.</translation> </message> - </context> + <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> GB</source> + <translation type="unfinished">જીબી (GB)</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બà«àª²à«‹àª• ચેન (સાંકળ) (%2GB) માં સૌથી પહેલાના વà«àª¯àªµàª¹àª¾àª°à«‹àª¥à«€ શરૂ થાય છે%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> + </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> - </context> + <message> + <source>Esc</source> + <translation type="unfinished">Esc (બહાર)</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>&Main</source> + <translation type="unfinished">&મà«àª–à«àª¯</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation type="unfinished">સિસà«àªŸàª®àª®àª¾àª‚ લોગ ઇન કરà«àª¯àª¾ પછી આપમેળે %1 શરૂ કરો.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation type="unfinished">સિસà«àªŸàª® લૉગિન પર %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 &database cache</source> + <translation type="unfinished">&ડેટાબેઠકેશનà«àª‚ કદ</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation type="unfinished">સà«àª•à«àª°àª¿àªªà«àªŸ અને ચકાસણી દોરિયોની સંખà«àª¯àª¾</translation> + </message> + <message> + <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">%1 સà«àª¸àª‚ગત સà«àª•à«àª°àª¿àªªà«àªŸàª¨à«‹ સંપૂરà«àª£ મારà«àª— (દા.ત. C:\Downloads\hwi.exe અથવા /Users/you/Downloads/hwi.py). સાવચેત રહો: ​​માલવેર તમારા સિકà«àª•àª¾ ચોરી શકે છે!</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>Font in the Overview tab: </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>&Reset Options</source> + <translation type="unfinished">&રીસેટ વિકલà«àªªà«‹</translation> + </message> + <message> + <source>&Network</source> + <translation type="unfinished">&નેટવરà«àª•</translation> + </message> + <message> + <source>Prune &block storage to</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">મહતà«àª¤àª® ડેટાબેઠકેશ કદ. àªàª• મોટી કેશ àªàª¡àªªà«€ સમનà«àªµàª¯àª¨àª®àª¾àª‚ યોગદાન આપી શકે છે, જે પછી મોટાàªàª¾àª—ના ઉપયોગના કેસોમાં લાઠઓછો ઉચà«àªšàª¾àª°àªµàª¾àª®àª¾àª‚ આવે છે. કેશનà«àª‚ કદ ઘટાડવાથી મેમરીનો વપરાશ ઘટશે. આ કેશ માટે નહિ વપરાયેલ મેમà«àªªà«‚લ મેમરી શેર કરવામાં આવી છે.</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, <0 = leave that many cores free)</source> + <translation type="unfinished">(0 = ઓટો, <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&PC server</source> + <extracomment>An Options window setting to enable the RPC server.</extracomment> + <translation type="unfinished">R&PC સરà«àªµàª° સકà«àª·àª® કરો</translation> + </message> + <message> + <source>W&allet</source> + <translation type="unfinished">વૉલેટ</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 &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> + <message> + <source>Enable coin &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>&Spend unconfirmed change</source> + <translation type="unfinished">&અપà«àª°àª®àª¾àª£àª¿àª¤ ફેરફાર ખરà«àªšà«‹</translation> + </message> + <message> + <source>Enable &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>&External signer script path</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> + <message> + <source>Map port using &UPnP</source> + <translation type="unfinished">&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&T-PMP</source> + <translation type="unfinished">NA&T-PMP નો ઉપયોગ કરીને નકશો પોરà«àªŸ</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation type="unfinished">બહારથી જોડાણો સà«àªµà«€àª•àª¾àª°à«‹.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation type="unfinished">ઇનકમિંગ કનેકà«àª¶àª¨à«àª¸àª¨à«‡ મંજૂરી આપો</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation type="unfinished">SOCKS5 પà«àª°à«‹àª•à«àª¸à«€ દà«àªµàª¾àª°àª¾ Bitcoin નેટવરà«àª•àª¥à«€ કનેકà«àªŸ થાઓ.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation type="unfinished">SOCKS5 પà«àª°à«‹àª•à«àª¸à«€ (ડિફોલà«àªŸ પà«àª°à«‹àª•à«àª¸à«€) દà«àªµàª¾àª°àª¾ &કનેકà«àªŸ કરો:</translation> + </message> + <message> + <source>Proxy &IP:</source> + <translation type="unfinished">પà«àª°à«‹àª•à«àª¸à«€ IP:</translation> + </message> + <message> + <source>&Port:</source> + <translation type="unfinished">&પોરà«àªŸ:</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>&Window</source> + <translation type="unfinished">&બારી</translation> + </message> + <message> + <source>Show the icon in the system tray.</source> + <translation type="unfinished">સિસà«àªŸàª® ટà«àª°à«‡àª®àª¾àª‚ ચિહà«àª¨ બતાવો.</translation> + </message> + <message> + <source>&Show tray icon</source> + <translation type="unfinished">&ટà«àª°à«‡ આઇકન બતાવો</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation type="unfinished">વિનà«àª¡à«‹àª¨à«‡ નાની કરà«àª¯àª¾ પછી માતà«àª° ટà«àª°à«‡ આઇકોન બતાવો.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation type="unfinished">&ટાસà«àª•àª¬àª¾àª°àª¨à«‡ બદલે ટà«àª°à«‡àª®àª¾àª‚ નાની કરો</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation type="unfinished">બંધ થવા પર નાનà«àª‚ કરો</translation> + </message> + <message> + <source>&Display</source> + <translation type="unfinished">&પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરો</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation type="unfinished">વપરાશકરà«àª¤àª¾ ઈનà«àªŸàª°àª«à«‡àª¸ અને àªàª¾àª·àª¾:</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>&Unit to show amounts in:</source> + <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> + </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 (દા.ત. બà«àª²à«‹àª• àªàª•à«àª¸àªªà«àª²à«‹àª°àª°) જે વà«àª¯àªµàª¹àª¾àª°à«‹ ટેબમાં સંદરà«àª મેનૂ આઇટમ તરીકે દેખાય છે. URL માં %s ટà«àª°àª¾àª¨à«àªà«‡àª•à«àª¶àª¨ હેશ દà«àªµàª¾àª°àª¾ બદલવામાં આવે છે. બહà«àªµàª¿àª§ URL ને વરà«àªŸàª¿àª•àª² બાર દà«àªµàª¾àª°àª¾ અલગ કરવામાં આવે છે |.</translation> + </message> + <message> + <source>&Third-party transaction URLs</source> + <translation type="unfinished">&તૃતીય-પકà«àª· વà«àª¯àªµàª¹àª¾àª° URLs</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">ટોર ઓનિયન સેવાઓ માટે અલગ SOCKS5 પà«àª°à«‹àª•à«àª¸à«€ દà«àªµàª¾àª°àª¾ બિટકોઇન નેટવરà«àª• સાથે કનેકà«àªŸ થાઓ.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation type="unfinished">ટોર ઓનિયન સેવાઓ દà«àªµàª¾àª°àª¾ સાથીદારો સà«àª§à«€ પહોંચવા માટે અલગ SOCKS&5 પà«àª°à«‹àª•à«àª¸à«€àª¨à«‹ ઉપયોગ કરો:</translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&બરાબર</translation> + </message> + <message> + <source>&Cancel</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>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> + <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->Mask values.</source> + <translation type="unfinished">વિહંગાવલોકન ટેબ માટે ગોપનીયતા મોડ સકà«àª°àª¿àª¯ કરà«àª¯à«‹. મૂલà«àª¯à«‹àª¨à«‡ અનમાસà«àª• કરવા માટે, સેટિંગà«àª¸->માસà«àª• મૂલà«àª¯à«‹àª¨à«‡ અનચેક કરો.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>PSBT Operations</source> + <translation type="unfinished">PSBT કામગીરી</translation> + </message> + <message> + <source>Sign Tx</source> + <translation type="unfinished">સાઇન Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation type="unfinished">બà«àª°à«‹àª¡àª•àª¾àª¸à«àªŸ Tx</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>own address</source> + <translation type="unfinished">પોતાનà«àª‚ સરનામà«àª‚</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>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 વિશà«àª²à«‡àª·àª¿àª¤ કરી શકાતà«àª‚ નથી! આ અમાનà«àª¯ Bitcoin સરનામà«àª‚ અથવા દૂષિત 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> @@ -338,6 +2197,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> @@ -349,30 +2213,657 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>QRImageWidget</name> + <message> + <source>&Save Image…</source> + <translation type="unfinished">&છબી સાચવો…</translation> + </message> + <message> + <source>&Copy Image</source> + <translation type="unfinished">&છબી કોપી કરો</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">QR કોડમાં URI ને àªàª¨à«àª•à«‹àª¡ કરવામાં àªà«‚લ.</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>&Information</source> + <translation type="unfinished">&માહિતી</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>&Reset</source> + <translation type="unfinished">&રીસેટ કરો</translation> + </message> + <message> + <source>Received</source> + <translation type="unfinished">પà«àª°àª¾àªªà«àª¤</translation> + </message> + <message> <source>Sent</source> <translation type="unfinished">મોકલેલ</translation> </message> - </context> + <message> + <source>&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>The transport layer version: %1</source> + <translation type="unfinished">પરિવહન સà«àª¤àª° સંસà«àª•àª°àª£:%1</translation> + </message> + <message> + <source>Transport</source> + <translation type="unfinished">પરિવહન</translation> + </message> + <message> + <source>The BIP324 session ID string in hex, if any.</source> + <translation type="unfinished">હેકà«àª¸àª®àª¾àª‚ BIP324 સતà«àª° ID સà«àªŸà«àª°àª¿àª‚ગ, જો કોઈ હોય તો.</translation> + </message> + <message> + <source>Session ID</source> + <translation type="unfinished">પà«àª°àª•à«àª°àª¿àª¯àª¾ નંબર</translation> + </message> + <message> + <source>Version</source> + <translation type="unfinished">સંસà«àª•àª°àª£</translation> + </message> + <message> + <source>Whether we relay transactions to this peer.</source> + <translation type="unfinished">શà«àª‚ આપણે આ પીઅરને વà«àª¯àªµàª¹àª¾àª°à«‹ રીલે કરીઠછીàª.</translation> + </message> + <message> + <source>Transaction Relay</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>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">પિંગ સમય</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation type="unfinished">હાલમાં બાકી પિંગનો સમયગાળો.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation type="unfinished">પિંગ રાહ જà«àª“</translation> + </message> + <message> + <source>Min Ping</source> + <translation type="unfinished">નà«àª¯à«‚નતમ પિંગ</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>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>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">શોધવà«àª‚: પીઅર v1 અથવા v2 હોઈ શકે છે</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: àªàª¨àª•à«àª°àª¿àªªà«àªŸà«‡àª¡, પà«àª²à«‡àª¨àªŸà«‡àª•à«àª¸à«àªŸ ટà«àª°àª¾àª¨à«àª¸àªªà«‹àª°à«àªŸ પà«àª°à«‹àªŸà«‹àª•à«‹àª²</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: BIP324 àªàª¨à«àª•à«àª°àª¿àªªà«àªŸà«‡àª¡ ટà«àª°àª¾àª¨à«àª¸àªªà«‹àª°à«àªŸ પà«àª°à«‹àªŸà«‹àª•à«‹àª²</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>Ctrl++</source> + <extracomment>Main shortcut to increase the RPC console font size.</extracomment> + <translation type="unfinished">કંટà«àª°à«‹àª²++</translation> + </message> + <message> + <source>Ctrl+=</source> + <extracomment>Secondary shortcut to increase the RPC console font size.</extracomment> + <translation type="unfinished">કંટà«àª°à«‹àª²+=</translation> + </message> + <message> + <source>Ctrl+-</source> + <extracomment>Main shortcut to decrease the RPC console font size.</extracomment> + <translation type="unfinished">કંટà«àª°à«‹àª²+-</translation> + </message> + <message> + <source>Ctrl+_</source> + <extracomment>Secondary shortcut to decrease the RPC console font size.</extracomment> + <translation type="unfinished">કંટà«àª°à«‹àª²+_</translation> + </message> + <message> + <source>&Copy address</source> + <extracomment>Context menu action to copy the address of a peer.</extracomment> + <translation type="unfinished">સરનામà«àª‚ &નકલ કરો</translation> + </message> + <message> + <source>&Disconnect</source> + <translation type="unfinished">&ડિસà«àª•àª¨à«‡àª•à«àªŸ</translation> + </message> + <message> + <source>1 &hour</source> + <translation type="unfinished">1 &કલાક</translation> + </message> + <message> + <source>1 d&ay</source> + <translation type="unfinished">1 &દિવસ</translation> + </message> + <message> + <source>1 &week</source> + <translation type="unfinished">1 &અઠવાડિયà«àª‚</translation> + </message> + <message> + <source>1 &year</source> + <translation type="unfinished">1 &વરà«àª·</translation> + </message> + <message> + <source>&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>&Unban</source> + <translation type="unfinished">&અપà«àª°àª¤àª¿àª¬àª‚ધ</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>Ctrl+I</source> + <translation type="unfinished">કંટà«àª°à«‹àª²+I</translation> + </message> + <message> + <source>Ctrl+T</source> + <translation type="unfinished">કંટà«àª°à«‹àª²+T</translation> + </message> + <message> + <source>Ctrl+N</source> + <translation type="unfinished">કંટà«àª°à«‹àª²+N</translation> + </message> + <message> + <source>Ctrl+P</source> + <translation type="unfinished">કંટà«àª°à«‹àª²+P</translation> + </message> + <message> + <source>Node window - [%1]</source> + <translation type="unfinished">નોડ વિનà«àª¡à«‹- [%1]</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>&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>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> + </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 <b>optional</b>.</source> + <translation type="unfinished">ચà«àª•àªµàª£à«€àª¨à«€ વિનંતી કરવા માટે આ ફોરà«àª®àª¨à«‹ ઉપયોગ કરો. બધા કà«àª·à«‡àª¤à«àª°à«‹ <b>વૈકલà«àªªàª¿àª•</b> છે.</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>&Create new receiving address</source> + <translation type="unfinished">&નવà«àª‚ પà«àª°àª¾àªªà«àª¤ કરવાનà«àª‚ સરનામà«àª‚ બનાવો</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 &URI</source> + <translation type="unfinished">કૉપિ &URI </translation> + </message> + <message> + <source>&Copy address</source> + <translation type="unfinished">સરનામà«àª‚ &નકલ કરો</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">કૉપિ કરો &લેબલ બનાવો</translation> + </message> + <message> + <source>Copy &message</source> + <translation type="unfinished">નકલ & સંદેશ</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">નકલ &રકમ</translation> + </message> + <message> + <source>Not recommended due to higher fees and less protection against typos.</source> + <translation type="unfinished">વધૠફી અને ટાઇપો સામે ઓછા રકà«àª·àª£àª¨à«‡ કારણે àªàª²àª¾àª®àª£ કરવામાં આવતી નથી.</translation> + </message> + <message> + <source>Generates an address compatible with older wallets.</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>Wallet:</source> + <translation type="unfinished">વૉલેટ:</translation> + </message> + <message> + <source>Copy &URI</source> + <translation type="unfinished">&URI કૉપિ કરો</translation> + </message> + <message> + <source>&Save Image…</source> + <translation type="unfinished">&છબી સાચવો…</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> @@ -384,9 +2875,78 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>SendCoinsDialog</name> <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>Hide</source> <translation type="unfinished">છà«àªªàª¾àªµà«‹</translation> </message> + <message> + <source>Clear all fields of the form.</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 change</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>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"> @@ -400,7 +2960,45 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>SendCoinsEntry</name> + <message> + <source>&Label:</source> + <translation type="unfinished">&લેબલ:</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation type="unfinished">કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡àª®àª¾àª‚થી સરનામà«àª‚ પેસà«àªŸ કરો</translation> + </message> + </context> +<context> + <name>SignVerifyMessageDialog</name> + <message> + <source>Paste address from clipboard</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> + <source>own address</source> + <translation type="unfinished">પોતાનà«àª‚ સરનામà«àª‚</translation> + </message> <message numerus="yes"> <source>matures in %n more block(s)</source> <translation type="unfinished"> @@ -416,6 +3014,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>TransactionTableModel</name> <message> + <source>Date</source> + <translation type="unfinished">તારીખ</translation> + </message> + <message> <source>Type</source> <translation type="unfinished">પà«àª°àª•àª¾àª°</translation> </message> @@ -431,11 +3033,31 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>TransactionView</name> <message> + <source>&Copy address</source> + <translation type="unfinished">સરનામà«àª‚ &નકલ કરો</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">કૉપિ કરો &લેબલ બનાવો</translation> + </message> + <message> + <source>Copy &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> </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> @@ -458,8 +3080,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Create a new wallet</source> <translation type="unfinished">નવà«àª‚ વૉલેટ બનાવો</translation> </message> + <message> + <source>Error</source> + <translation type="unfinished">àªà«‚લ</translation> + </message> </context> <context> + <name>WalletModel</name> + <message> + <source>default wallet</source> + <translation type="unfinished">ડિફૉલà«àªŸ વૉલેટ</translation> + </message> +</context> +<context> <name>WalletView</name> <message> <source>&Export</source> @@ -469,5 +3102,14 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>Export the data in the current tab to a file</source> <translation type="unfinished">હાલ માં પસંદ કરેલ માહિતી ને ફાઇલમાં નિકાસ કરો</translation> </message> - </context> + <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_hi.ts b/src/qt/locale/bitcoin_hi.ts index 414670e7a2..bcde979223 100644 --- a/src/qt/locale/bitcoin_hi.ts +++ b/src/qt/locale/bitcoin_hi.ts @@ -533,6 +533,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> + <source>Error creating wallet</source> + <translation type="unfinished">बटवा निरà¥à¤®à¤¾à¤£ में गलती</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">तà¥à¤°à¥à¤Ÿà¤¿: %1</translation> </message> @@ -682,6 +686,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>MigrateWalletActivity</name> <message> + <source>Migrate wallet</source> + <translation type="unfinished">वॉलेट माइगà¥à¤°à¥‡à¤Ÿ करें</translation> + </message> + <message> <source>Migrate Wallet</source> <translation type="unfinished">वॉलेट माइगà¥à¤°à¥‡à¤Ÿ करें</translation> </message> @@ -695,6 +703,13 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>CreateWalletDialog</name> + <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">आपके नठबटवे के निरà¥à¤®à¤¾à¤£ से आप सिरà¥à¤« à¤à¤• कदम दूर है</translation> + </message> + </context> +<context> <name>Intro</name> <message numerus="yes"> <source>%n GB of space available</source> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index a2f27b94a0..55dc10bb72 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -303,6 +303,18 @@ AláÃrni csak régi tÃpusú, egyessel kezdÅ‘dÅ‘ cÃmekkel lehet.</translation> <translation type="unfinished">ismeretlen</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Beágyazva "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Alapértelmezett betűtÃpus "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Egyedi…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Összeg</translation> </message> @@ -1598,6 +1610,10 @@ A migrációs folyamat készÃt biztonsági mentést a tárcáról migrálás el <translation type="unfinished">Az alkalmazásból való kilépés helyett az eszköztárba kicsinyÃti az alkalmazást az ablak bezárásakor. Ez esetben az alkalmazás csak a Kilépés menüponttal zárható be.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">A FÅ‘oldal fül betűtÃpusa:</translation> + </message> + <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">Ebben az ablakban megadott beállÃtások felülbÃrálásra kerültek a parancssori kapcsolók által:</translation> </message> @@ -2635,6 +2651,10 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished">Parancs végrehajtása tárca nélkül</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Node ablak - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Parancs végrehajtása a "%1" tárca használatával</translation> </message> @@ -4453,6 +4473,10 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">A %s elérési úton fájl nem létezik.</translation> </message> <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Hiba tietokannan transaktion vahvistamisessa lompakon tapahtumien poistamiseksi.</translation> + </message> + <message> <source>Error creating %s</source> <translation type="unfinished">Hiba %s létrehozása közben</translation> </message> @@ -4501,6 +4525,10 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">A tárca-adatbázisból a következÅ‘ rekord beolvasása sikertelen.</translation> </message> <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Hinta tietokannan transaktion aloittamisessa lompakon tapahtumien poistamiseksi.</translation> + </message> + <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> <translation type="unfinished">Hiba: Nem lehet kinyerni a célt az előállÃtott scriptpubkey-bÅ‘l</translation> </message> @@ -4585,6 +4613,14 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">Hiba: Nem lehet Ãrni a figyelÅ‘ tárca legfelsÅ‘ blokkját megadó rekordot</translation> </message> <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Virhe: osoitekirjan kopioiminen epäonnistui lompakolle %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Virhe: tietokantatransaktiota ei voida suorittaa lompakolle %s</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Egyik hálózati portot sem sikerül figyelni. Használja a -listen=0 kapcsolót, ha ezt szeretné.</translation> </message> @@ -4601,6 +4637,11 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">Adatbázis ellenÅ‘rzése sikertelen</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished"> +Virhe tapahtuman poistamisessa: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">A választott dÃj (%s) alacsonyabb mint a beállÃtott minimum dÃj (%s)</translation> </message> @@ -4821,6 +4862,10 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">Ez a tranzakció dÃja, amelyet kifizet, ha tranzakciót indÃt.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">tranzakció%s ei kuulu tähän lompakkoon.</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Tranzakció összege túl alacsony</translation> </message> @@ -4929,6 +4974,10 @@ A tárca biztonsági mentésének visszaállÃtása sikertelen.</translation> <translation type="unfinished">Hiba: Nem sikerült hozzáadni a megfigyelt %s tranzakciót a figyelÅ‘ tárcához</translation> </message> <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Virhe: Ei voitu poistaa vain seurantatapahtumia.</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> diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts index 975959d8b5..a148483336 100644 --- a/src/qt/locale/bitcoin_id.ts +++ b/src/qt/locale/bitcoin_id.ts @@ -259,6 +259,18 @@ Tanda tangan hanya bisa digunakan dengan tipe alamat 'warisan'</translation> <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">Error yang fatal telah terjadi. Periksa bahwa file pengaturan dapat ditulis atau coba jalankan dengan -nosettings</translation> </message> + <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Di embed "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Font bawaan sistem "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Pilihan...</translation> + </message> <message numerus="yes"> <source>%n second(s)</source> <translation type="unfinished"> @@ -553,6 +565,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <translation type="unfinished">Skrip hanya lihat telah dimigrasikan ke dompet yang baru '%1'.</translation> </message> <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Skrip hanya lihat telah diimigrasikan ke dompet baru yang bernama '%1'.</translation> + </message> + <message> <source>Migration failed</source> <translation type="unfinished">Migrasi gagal</translation> </message> @@ -974,6 +990,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <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>Font in the Overview tab: </source> + <translation type="unfinished">Font pada tab Overview:</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> @@ -1112,6 +1132,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <source>PSBT Operations</source> <translation type="unfinished">Operasi PBST</translation> </message> + <message> + <source>Sends %1 to %2</source> + <translation type="unfinished">Mengirim %1 ke %2</translation> + </message> </context> <context> <name>PeerTableModel</name> @@ -1244,6 +1268,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <translation type="unfinished">Salin Perubahan</translation> </message> <message> + <source>%1 from wallet '%2'</source> + <translation type="unfinished">%1 dari dompet '%2'</translation> + </message> + <message> <source>Unsigned Transaction</source> <comment>PSBT copied</comment> <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> @@ -1286,6 +1314,10 @@ Proses migrasi akan mencadangkan dompet sebelum melakukan pemindahan. Fail cadan <numerusform>matures in %n more block(s)</numerusform> </translation> </message> + <message> + <source>%1 (Certificate was not verified)</source> + <translation type="unfinished">%1 (Sertifikat tidak terverifikasi)</translation> + </message> </context> <context> <name>TransactionTableModel</name> @@ -1507,10 +1539,18 @@ Tidak dapat memulihkan cadangan dompet..</translation> <translation type="unfinished">Verifikasi Blok terganggu</translation> </message> <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Kesalahan dalam melakukan db txn untuk penghapusan transaksi dompet</translation> + </message> + <message> <source>Error reading configuration file: %s</source> <translation type="unfinished">Kesalahan membaca file konfigurasi: %s</translation> </message> <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Kesalahan memulai db txn untuk penghapusan transaksi dompet</translation> + </message> + <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> <translation type="unfinished">Eror: Tidak dapat mengekstrak destinasi dari scriptpubkey yang dibuat</translation> </message> @@ -1539,14 +1579,38 @@ Tidak dapat memulihkan cadangan dompet..</translation> <translation type="unfinished">Kesalahan: Tidak dapat membaca semua catatan dalam database</translation> </message> <message> + <source>Error: Unable to read wallet's best block locator record</source> + <translation type="unfinished">Kesalahan: Tidak dapat membaca catatan pencari blok terbaik dompet</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 solvable wallet best block locator record</source> + <translation type="unfinished">Kesalahan: Tidak dapat menulis catatan pencari blok terbaik dompet solvable</translation> + </message> + <message> + <source>Error: Unable to write watchonly wallet best block locator record</source> + <translation type="unfinished">Kesalahan: Tidak dapat menulis catatan pencari blok terbaik dompet watchonly</translation> + </message> + <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Kesalahan: penyalinan daftar kontak gagal untuk dompet %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Kesalahan: database transaksi tidak dapat dilakukan untuk dompet %s</translation> + </message> + <message> <source>Failed to start indexes, shutting down..</source> <translation type="unfinished">Gagal memulai indeks, mematikan..</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Gagal menghapus transaksi: %s</translation> + </message> + <message> <source>Insufficient dbcache for block verification</source> <translation type="unfinished">Kekurangan dbcache untuk verifikasi blok</translation> </message> @@ -1583,6 +1647,10 @@ Tidak dapat memulihkan cadangan dompet..</translation> <translation type="unfinished">Direktori data yang ditentukan "%s" tidak ada.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Transaksi %s tidak termasuk dompet ini</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> @@ -1599,8 +1667,20 @@ Tidak dapat memulihkan cadangan dompet..</translation> <translation type="unfinished">Tingkat penebangan global yang tidak didukung %s = %s. Nilai yang valid: %s.</translation> </message> <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Pembuatan berkas dompet gagal: %s</translation> + </message> + <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> <translation type="unfinished">menerima estimasi biaya basi tidak didukung pada %s rantai.</translation> </message> + <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">Kesalahan: Tidak mampu menambahkan watchonly tx %s ke dompet watchonly</translation> + </message> + <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Kesalahan: Tidak mampu menghapus transaksi watchonly.</translation> + </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index bdd23b7c04..1a92e34bb2 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -303,6 +303,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ä¸æ˜Ž</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">埋込㿠"%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">デフォルトシステムフォント "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">カスタム…</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">金é¡</translation> </message> @@ -1594,6 +1606,10 @@ The migration process will create a backup of the wallet before migrating. This <translation type="unfinished">ウィンドウãŒé–‰ã˜ã‚‰ã‚ŒãŸã¨ãã€ã‚¢ãƒ—リケーションを終了ã™ã‚‹ã®ã§ã¯ãªã最å°åŒ–ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒæœ‰åŠ¹ã®å ´åˆã€ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‹ã‚‰çµ‚了ãŒé¸æŠžã•ã‚ŒãŸã¨ãã®ã¿ã‚¢ãƒ—リケーションãŒçµ‚了ã—ã¾ã™ã€‚</translation> </message> <message> + <source>Font in the Overview tab: </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> @@ -2637,6 +2653,10 @@ BIP70ã«ã¯åºƒç¯„ãªã‚»ã‚ュリティー上ã®å•é¡ŒãŒã‚ã‚‹ã®ã§ã€ã‚¦ã‚©ãƒ¬ <translation type="unfinished">ã©ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã‚‚使ã‚ãšã«ã‚³ãƒžãƒ³ãƒ‰ã‚’実行ã—ã¦ã„ã¾ã™</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">ノードウィンドウ - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">"%1" ウォレットを使ã£ã¦ã‚³ãƒžãƒ³ãƒ‰ã‚’実行ã—ã¦ã„ã¾ã™</translation> </message> @@ -4457,6 +4477,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ダンプファイル %s ãŒå˜åœ¨ã—ã¾ã›ã‚“。</translation> </message> <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">ウォレットトランザクションã®å‰Šé™¤ã®ãŸã‚db txnã®ã‚³ãƒŸãƒƒãƒˆä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ</translation> + </message> + <message> <source>Error creating %s</source> <translation type="unfinished">%sã®ä½œæˆã‚¨ãƒ©ãƒ¼</translation> </message> @@ -4505,6 +4529,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ウォレットデータベースã‹ã‚‰æ¬¡ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã®èªã¿å–ã‚Šã§ã‚¨ãƒ©ãƒ¼</translation> </message> <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">ウォレットトランザクションã®å‰Šé™¤ã®ãŸã‚ã®db txnã®é–‹å§‹ã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ</translation> + </message> + <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> <translation type="unfinished">エラー: 生æˆã•ã‚ŒãŸscriptpubkeyã‹ã‚‰å®›å…ˆã‚’抽出ã§ãã¾ã›ã‚“</translation> </message> @@ -4589,6 +4617,14 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">エラー:監視専用ウォレットã®ãƒ™ã‚¹ãƒˆãƒ–ãƒãƒƒã‚¯ãƒã‚±ãƒ¼ã‚¿ãƒ¼ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’書ãè¾¼ã‚ã¾ã›ã‚“</translation> </message> <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">エラー: ウォレット%sã®ã‚¢ãƒ‰ãƒ¬ã‚¹å¸³ã®ã‚³ãƒ”ーã«å¤±æ•—ã—ã¾ã—ãŸ</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">エラー: ウォレット%sã«å¯¾ã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’実行ã§ãã¾ã›ã‚“</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> @@ -4605,6 +4641,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">データベースã®æ¤œè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸ</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">å–引ã®å‰Šé™¤ã«å¤±æ•—: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">手数料率(%s)ãŒæœ€ä½Žæ‰‹æ•°æ–™çŽ‡ã®è¨å®š(%s)を下回ã£ã¦ã„ã¾ã™</translation> </message> @@ -4825,6 +4865,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">ã“ã‚Œã¯ã€å–引をé€ä¿¡ã™ã‚‹å ´åˆã«æ”¯æ‰•ã†å–引手数料ã§ã™ã€‚</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">å–引%sã¯ã“ã®ã‚¦ã‚©ãƒ¬ãƒƒãƒˆã®ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">å–引ã®é‡‘é¡ãŒå°ã•ã™ãŽã¾ã™</translation> </message> @@ -4933,6 +4977,10 @@ Unable to restore backup of wallet.</source> <translation type="unfinished">エラー: 監視対象å–引%sを監視専用ウォレットã«è¿½åŠ ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation> </message> <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">エラー: 監視対象å–引を削除ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation> + </message> + <message> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished">ユーザエージェントã®ã‚³ãƒ¡ãƒ³ãƒˆ ( %s ) ã«å®‰å…¨ã§ãªã„æ–‡å—ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚</translation> </message> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index eaf3c35f2d..40964a4d31 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -188,43 +188,43 @@ <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> @@ -325,8 +325,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> @@ -361,8 +361,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> @@ -464,30 +464,30 @@ <message numerus="yes"> <source>%n GB of space available</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <numerusform>%n GB of space available</numerusform> + <numerusform>%n GB of space available</numerusform> </translation> </message> <message numerus="yes"> <source>(of %n GB needed)</source> <translation type="unfinished"> - <numerusform /> - <numerusform /> + <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 /> - <numerusform /> + <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"> - <numerusform /> - <numerusform /> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> + <numerusform>(sufficient to restore backups %n day(s) old)</numerusform> </translation> </message> </context> @@ -872,8 +872,8 @@ <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> @@ -1066,8 +1066,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> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index 0df3a165aa..1b7471cd92 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -94,6 +94,10 @@ PasiraÅ¡ymas galimas tik su 'legacy' tipo adresais.</translation> <translation type="unfinished">Bandant iÅ¡saugoti adresų sÄ…raÅ¡Ä… - įvyko klaida keliant į %1. PraÅ¡ome bandyti dar kartÄ….</translation> </message> <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Gaunami adresai - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Eksportavimas nepavyko</translation> </message> diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts index 2bb0d996df..675e8da4a8 100644 --- a/src/qt/locale/bitcoin_ml.ts +++ b/src/qt/locale/bitcoin_ml.ts @@ -265,6 +265,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: %1</source> <translation type="unfinished">തെറàµà´±àµ : %1 </translation> </message> @@ -380,6 +390,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ഒരൠപàµà´¤à´¿à´¯ വാലറàµà´±àµ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´•</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished"> à´’à´ªàµà´ªà´‚ ചെറàµà´¤à´¾à´•àµà´•àµà´•</translation> + </message> + <message> <source>Wallet:</source> <translation type="unfinished">പണസഞàµà´šà´¿ </translation> </message> @@ -417,18 +431,46 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">ഇഷàµâ€Œà´Ÿà´®àµà´³àµà´³à´¤àµâ€Œ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•à´²àµâ€</translation> </message> <message> + <source>&Encrypt Wallet…</source> + <translation type="unfinished">വാലറàµà´±àµ എൻകàµà´°à´¿à´ªàµà´±àµà´±àµ ചെയàµà´¯àµà´•â€¦</translation> + </message> + <message> <source>Encrypt the private keys that belong to your wallet</source> <translation type="unfinished">നിങàµà´™à´³àµà´Ÿàµ† വാലറàµà´±à´¿à´¨àµà´±àµ† à´¸àµà´µà´•à´¾à´°àµà´¯ കീകൾ എൻ‌കàµà´°à´¿à´ªàµà´±àµà´±àµ ചെയàµà´¯àµà´•</translation> </message> <message> + <source>&Backup Wallet…</source> + <translation type="unfinished"> ബാകàµà´•à´ªàµà´ªàµ വാലറàµà´±àµà´‚…</translation> + </message> + <message> + <source>&Change Passphrase…</source> + <translation type="unfinished">പാസàµà´«àµà´°àµ†à´¯àµà´¸àµ മാറàµà´±àµà´•</translation> + </message> + <message> + <source>Sign &message…</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 message…</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>&Load PSBT from file…</source> + <translation type="unfinished"> à´¤àµà´±à´¨àµà´¨àµ URL</translation> + </message> + <message> + <source>Close Wallet…</source> + <translation type="unfinished">വാലറàµà´±àµ à´…à´Ÿà´¯àµà´•àµà´•àµà´•</translation> + </message> + <message> <source>&File</source> <translation type="unfinished">& ഫയൽ</translation> </message> @@ -445,6 +487,10 @@ 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>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished">പേയàµâ€Œà´®àµ†à´¨àµà´±àµà´•àµ¾ à´…à´àµà´¯àµ¼à´¤àµà´¥à´¿à´•àµà´•àµà´• (QR കോഡàµà´•à´³àµà´‚ ബിറàµà´±àµà´•àµ‹à´¯à´¿à´¨àµà´‚ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨àµ: URI- കൾ)</translation> </message> @@ -532,6 +578,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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> @@ -556,6 +607,11 @@ 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>Restore Wallet</source> <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> <translation type="unfinished">വാലറàµà´±àµ à´ªàµà´¨à´ƒà´¸àµà´¥à´¾à´ªà´¿à´•àµà´•àµà´•</translation> @@ -590,6 +646,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </translation> </message> <message> + <source>Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished">à´ªàµà´¤à´¿à´¯ വാലറàµà´±àµ സൃഷàµà´Ÿà´¿à´•àµà´•à´¾àµ» കഴിയിലàµà´², à´¸àµâ€Œà´•àµà´²àµˆà´±àµà´±àµ +പിനàµà´¤àµà´£à´¯à´¿à´²àµà´²à´¾à´¤àµ† സോഫàµâ€Œà´±àµà´±àµâ€Œà´µàµ†à´¯àµ¼ കംപൈൽ ചെയàµâ€Œà´¤àµ (à´¡à´¿à´¸àµâ€Œà´•àµà´°à´¿à´ªàµâ€Œà´±àµà´±àµ¼ വാലറàµà´±àµà´•àµ¾à´•àµà´•àµ ആവശàµà´¯à´®à´¾à´£àµ)</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">തെറàµà´±àµ : %1 </translation> </message> diff --git a/src/qt/locale/bitcoin_ms.ts b/src/qt/locale/bitcoin_ms.ts index 9d20510264..613a118e45 100644 --- a/src/qt/locale/bitcoin_ms.ts +++ b/src/qt/locale/bitcoin_ms.ts @@ -81,6 +81,10 @@ Alihkan fail data ke dalam tab semasa</translation> <translation type="unfinished">Terdapat ralat semasa cubaan menyimpan senarai alamat kepada %1. Sila cuba lagi.</translation> </message> <message> + <source>Receiving addresses - %1</source> + <translation type="unfinished">Alamat Terima - %1</translation> + </message> + <message> <source>Exporting Failed</source> <translation type="unfinished">Mengeksport Gagal</translation> </message> diff --git a/src/qt/locale/bitcoin_my.ts b/src/qt/locale/bitcoin_my.ts index 0e546f3741..0d15317d1a 100644 --- a/src/qt/locale/bitcoin_my.ts +++ b/src/qt/locale/bitcoin_my.ts @@ -78,6 +78,37 @@ </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> + </context> +<context> <name>QObject</name> <message> <source>Error: %1</source> diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index e0e3e3a138..eec0318d3c 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -299,6 +299,18 @@ Ondertekenen is alleen mogelijk met adressen van het type 'legacy'.</translation <translation type="unfinished">onbekend</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Ingebed "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">Standaard systeemlettertype "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">Aangepast...</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Bedrag</translation> </message> @@ -1556,6 +1568,10 @@ Het migratieproces maakt voorafgaand aan het migreren een backup van de wallet. <translation type="unfinished">Minimaliseren in plaats van de applicatie af te sluiten wanneer het venster is afgesloten. Als deze optie is ingeschakeld, zal de toepassing pas worden afgesloten na het selecteren van Exit in het menu.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Lettertype in het Overzicht tab:</translation> + </message> + <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">Gekozen opties in dit dialoogvenster worden overschreven door de command line:</translation> </message> @@ -2543,6 +2559,10 @@ Als je deze fout ziet zou je de aanbieder moeten verzoeken om een BIP21-compatib <translation type="unfinished">Uitvoeren van commando zonder gebruik van een wallet</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Nodevenster - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Uitvoeren van commando met wallet "%1"</translation> </message> @@ -4278,6 +4298,10 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Dumpbestand %s bestaat niet.</translation> </message> <message> + <source>Error committing db txn for wallet transactions removal</source> + <translation type="unfinished">Fout bij db txn verwerking voor verwijderen wallet transacties</translation> + </message> + <message> <source>Error creating %s</source> <translation type="unfinished">Fout bij het maken van %s</translation> </message> @@ -4326,6 +4350,10 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Fout bij het lezen van het volgende record in de walletdatabase</translation> </message> <message> + <source>Error starting db txn for wallet transactions removal</source> + <translation type="unfinished">Fout bij starten db txn voor verwijderen wallet transacties</translation> + </message> + <message> <source>Error: Cannot extract destination from the generated scriptpubkey</source> <translation type="unfinished">Fout: Kan de bestemming niet extraheren uit de gegenereerde scriptpubkey</translation> </message> @@ -4410,6 +4438,14 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Fout: Kan beste block locatie aanduiding niet opslaan in alleen lezen wallet</translation> </message> <message> + <source>Error: address book copy failed for wallet %s</source> + <translation type="unfinished">Fout: Kopiëren adresboek mislukt voor wallet %s</translation> + </message> + <message> + <source>Error: database transaction cannot be executed for wallet %s</source> + <translation type="unfinished">Fout: Kan databasetransactie niet uitvoeren voor wallet %s</translation> + </message> + <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation type="unfinished">Mislukt om op welke poort dan ook te luisteren. Gebruik -listen=0 as u dit wilt.</translation> </message> @@ -4426,6 +4462,10 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Mislukt om de databank te controleren</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Verwijderen transactie mislukt: %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">Tarief (%s) is lager dan het minimum tarief (%s)</translation> </message> @@ -4646,6 +4686,10 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Dit is de transactievergoeding dat je betaalt wanneer je een transactie verstuurt.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Transactie %s behoort niet tot deze wallet</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Transactiebedrag te klein</translation> </message> @@ -4754,6 +4798,10 @@ Kan mislukte migratie niet opschonen</translation> <translation type="unfinished">Fout: Kon alleen lezen tx %s niet toevoegen aan alleen lezen wallet</translation> </message> <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">Fout: Kon alleen-lezen transacties niet verwijderen</translation> + </message> + <message> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished">User Agentcommentaar (%s) bevat onveilige karakters.</translation> </message> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index f1aab64ad2..dce4d498c5 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -257,6 +257,18 @@ Podpisywanie jest możliwe tylko z adresami typu 'legacy'.</translation> <translation type="unfinished">nieznane</translation> </message> <message> + <source>Embedded "%1"</source> + <translation type="unfinished">Osadzony "%1"</translation> + </message> + <message> + <source>Default system font "%1"</source> + <translation type="unfinished">DomyÅ›lna czcionka systemu "%1"</translation> + </message> + <message> + <source>Custom…</source> + <translation type="unfinished">WÅ‚asna:</translation> + </message> + <message> <source>Amount</source> <translation type="unfinished">Kwota</translation> </message> @@ -1062,6 +1074,14 @@ Proces migracji utworzy kopiÄ™ zapasowÄ… portfela przed migracjÄ…. Plik kopii za <translation type="unfinished">Portfel '%1' zostaÅ‚ poprawnie przeniesiony.</translation> </message> <message> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Skrypty tylko do odczytu zostaÅ‚y przeniesione do nowego portfela '%1'</translation> + </message> + <message> + <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Sprawne, ale nie oglÄ…dane skrypty tylko do odczytu zostaÅ‚y przeniesione do nowego portfela '%1'</translation> + </message> + <message> <source>Migration failed</source> <translation type="unfinished">Przeniesienie nie powiodÅ‚o siÄ™</translation> </message> @@ -1157,6 +1177,10 @@ Proces migracji utworzy kopiÄ™ zapasowÄ… portfela przed migracjÄ…. Plik kopii za <translation type="unfinished">JesteÅ› jeden krok od stworzenia swojego nowego portfela!</translation> </message> <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">ProszÄ™ podać nazwÄ™, i jeÅ›li potrzeba, wÅ‚Ä…cz zaawansowane ustawienia.</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Nazwa portfela</translation> </message> @@ -1544,6 +1568,10 @@ Proces migracji utworzy kopiÄ™ zapasowÄ… portfela przed migracjÄ…. Plik kopii za <translation type="unfinished">Minimalizuje zamiast zakoÅ„czyć dziaÅ‚anie programu przy zamykaniu okna. Kiedy ta opcja jest wÅ‚Ä…czona, program zakoÅ„czy dziaÅ‚anie po wybieraniu Zamknij w menu.</translation> </message> <message> + <source>Font in the Overview tab: </source> + <translation type="unfinished">Czcionka w zakÅ‚adce PrzeglÄ…d:</translation> + </message> + <message> <source>Options set in this dialog are overridden by the command line:</source> <translation type="unfinished">Opcje ustawione w tym oknie sÄ… nadpisane przez liniÄ™ komend:</translation> </message> @@ -2265,6 +2293,18 @@ JeÅ›li pojawia siÄ™ ten bÅ‚Ä…d, poproÅ› sprzedawcÄ™ o podanie URI zgodnego z BIP <translation type="unfinished">Wersja warstwy transportowej: %1</translation> </message> <message> + <source>Transport</source> + <translation type="unfinished">Transfer</translation> + </message> + <message> + <source>The BIP324 session ID string in hex, if any.</source> + <translation type="unfinished">ID sesji BIP324 jest szestnastkowym ciÄ…giem znaków, jeÅ›li istnieje.</translation> + </message> + <message> + <source>Session ID</source> + <translation type="unfinished">ID sesji</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Wersja</translation> </message> @@ -2559,6 +2599,10 @@ JeÅ›li pojawia siÄ™ ten bÅ‚Ä…d, poproÅ› sprzedawcÄ™ o podanie URI zgodnego z BIP <translation type="unfinished">WykonujÄ™ komendÄ™ bez portfela</translation> </message> <message> + <source>Node window - [%1]</source> + <translation type="unfinished">Okno wÄ™zÅ‚a - [%1]</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">WykonujÄ™ komendÄ™ używajÄ…c portfela "%1"</translation> </message> @@ -4012,6 +4056,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d: starsze portfele obsÅ‚ugujÄ… tylko typy adresów „legacyâ€, „p2sh-segwit†i „bech32â€</translation> </message> <message> + <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można wygenerować deskryptorów dla tego starego portfela. Upewnij siÄ™ najpierw, że portfel jest odblokowany.</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> @@ -4096,6 +4144,18 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Podano nieznany typ pliku portfela "%s". ProszÄ™ podać jeden z "bdb" lub "sqlite".</translation> </message> <message> + <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> + <translation type="unfinished">NieobsÅ‚ugiwany poziom rejestrowania specyficzny dla kategorii %1$s=%2$s. Oczekiwano %1$s=<category>:<loglevel>. Poprawne kategorie %3$s. Poprawne poziomy logowania: %4 $s.</translation> + </message> + <message> + <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> + <translation type="unfinished">Znaleziono nieobsÅ‚ugiwany format bazy danych chainstate. ProszÄ™ uruchomić ponownie z opcjÄ… -reindex-chainstate. To odbuduje bazÄ™ danych chainstate.</translation> + </message> + <message> + <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> + <translation type="unfinished">Portfel zostaÅ‚ zaÅ‚adowany pomyÅ›lnie. Starszy typ portfela jest przestarzaÅ‚y, a obsÅ‚uga tworzenia i otwierania starszych portfeli zostanie usuniÄ™ta w przyszÅ‚oÅ›ci. Starsze portfele można migrować do portfela deskryptora za pomocÄ… migratewallet.</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> @@ -4124,6 +4184,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Nie można rozpoznać -%s adresu: '%s'</translation> </message> <message> + <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> + <translation type="unfinished">Nie można ustawić -forcednsseed na true gdy ustawienie -dnsseed wynosi false.</translation> + </message> + <message> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> <translation type="unfinished">Nie można ustawić -peerblockfilters bez -blockfilterindex.</translation> </message> @@ -4132,6 +4196,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Nie mogÄ™ zapisać do katalogu danych '%s'; sprawdź uprawnienia.</translation> </message> <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">%sto bardzo dużo! Tak duże opÅ‚aty można uiÅ›cić w ramach jednej transakcji.</translation> + </message> + <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> <translation type="unfinished">Nie można jednoczeÅ›nie okreÅ›lić konkretnych poÅ‚Ä…czeÅ„ oraz pozwolić procesowi addrman na wyszukiwanie wychodzÄ…cych poÅ‚Ä…czeÅ„.</translation> </message> @@ -4148,10 +4216,42 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d: Podczas migracji utworzono zduplikowane deskryptory. Twój portfel może być uszkodzony.</translation> </message> <message> + <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> + <translation type="unfinished">Nie udaÅ‚o siÄ™ obliczyć opÅ‚at za uderzenia, ponieważ niepotwierdzone UTXO zależą od ogromnego skupiska niepotwierdzonych transakcji.</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>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">Estymacja opÅ‚at nieudana. DomyÅ›lna opÅ‚ata jest wyÅ‚Ä…czona. Poczekaj kilka bloków lub wÅ‚Ä…cz -%s.</translation> + </message> + <message> + <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> + <translation type="unfinished">PoÅ‚Ä…czenia wychodzÄ…ce ograniczone do CJDNS (-onlynet=cjdns), ale nie podano -cjdnsreachable</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">PoÅ‚Ä…czenia wychodzÄ…ce ograniczone do sieci Tor (-onlynet=onion), ale proxy do uzyskania dostÄ™pu do sieci Tor jest wyraźnie zabronione: -onion=0</translation> + </message> + <message> + <source> +Unable to cleanup failed migration</source> + <translation type="unfinished"> +Nie można wyczyÅ›cić nieudanej migracji</translation> + </message> + <message> + <source> +Unable to restore backup of wallet.</source> + <translation type="unfinished"> +Nie można przywrócić kopii zapasowej portfela</translation> + </message> + <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">Weryfikacja bloku zostaÅ‚a przerwana</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> @@ -4184,6 +4284,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Wczytywanie zakoÅ„czone</translation> </message> <message> + <source>Dump file %s does not exist.</source> + <translation type="unfinished">Plik zrzutu aplikacji %s nie istnieje.</translation> + </message> + <message> <source>Error creating %s</source> <translation type="unfinished">BÅ‚Ä…d podczas tworzenia %s</translation> </message> @@ -4220,6 +4324,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d otwierania bazy bloków</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">BÅ‚Ä…d: nie można odczytać pliku konfiguracyjnego: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">BÅ‚Ä…d odczytu z bazy danych, wyÅ‚Ä…czam siÄ™.</translation> </message> @@ -4228,6 +4336,14 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d odczytu kolejnego rekordu z bazy danych portfela</translation> </message> <message> + <source>Error: Cannot extract destination from the generated scriptpubkey</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można wyodrÄ™bnić miejsca docelowego z wygenerowanego scriptpubkey</translation> + </message> + <message> + <source>Error: Couldn't create cursor into database</source> + <translation type="unfinished">BÅ‚Ä…d: Nie udaÅ‚o siÄ™ utworzyć kursora w bazie danych</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> @@ -4236,6 +4352,18 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d: Plik zrzutu suma kontrolna nie pasuje. Obliczone %s, spodziewane %s</translation> </message> <message> + <source>Error: Failed to create new watchonly wallet</source> + <translation type="unfinished">BÅ‚Ä…d: Utworzenie portfela tylko do odczytu nie powiodÅ‚o siÄ™</translation> + </message> + <message> + <source>Error: Got key that was not hex: %s</source> + <translation type="unfinished">BÅ‚Ä…d: Otrzymana wartość nie jest szestnastkowa%s</translation> + </message> + <message> + <source>Error: Got value that was not hex: %s</source> + <translation type="unfinished">BÅ‚Ä…d: Otrzymana wartość nie jest szestnastkowa%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> @@ -4252,10 +4380,34 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">BÅ‚Ä…d: Ten portfel już używa SQLite</translation> </message> <message> + <source>Error: This wallet is already a descriptor wallet</source> + <translation type="unfinished">BÅ‚Ä…d: Ten portfel jest już portfelem opisowym (descriptor wallet)</translation> + </message> + <message> + <source>Error: Unable to begin reading all records in the database</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można odczytać wszystkich rekordów z bazy danych</translation> + </message> + <message> <source>Error: Unable to make a backup of your wallet</source> <translation type="unfinished">BÅ‚Ä…d: Nie mogÄ™ zrobić kopii twojego portfela</translation> </message> <message> + <source>Error: Unable to parse version %u as a uint32_t</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można zapisać wersji %u jako uint32_t</translation> + </message> + <message> + <source>Error: Unable to read all records in the database</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można odczytać wszystkich rekordów z bazy danych</translation> + </message> + <message> + <source>Error: Unable to read wallet's best block locator record</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można odczytać najlepszego rekordu lokalizatora bloków portfela</translation> + </message> + <message> + <source>Error: Unable to remove watchonly address book data</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można usunąć danych książki adresowej tylko do odczytu</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> @@ -4268,10 +4420,18 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Nie udaÅ‚o siÄ™ ponownie przeskanować portfela podczas inicjalizacji.</translation> </message> <message> + <source>Failed to start indexes, shutting down..</source> + <translation type="unfinished">Nie udaÅ‚o siÄ™ uruchomić indeksów, zamykanie...</translation> + </message> + <message> <source>Failed to verify database</source> <translation type="unfinished">Nie udaÅ‚o siÄ™ zweryfikować bazy danych</translation> </message> <message> + <source>Failure removing transaction: %s</source> + <translation type="unfinished">Nie udaÅ‚o siÄ™ usunąć transakcji %s</translation> + </message> + <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <translation type="unfinished">Wartość opÅ‚aty (%s) jest mniejsza niż wartość minimalna w ustawieniach (%s)</translation> </message> @@ -4296,6 +4456,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">WejÅ›cie nie znalezione lub już wydane</translation> </message> <message> + <source>Insufficient dbcache for block verification</source> + <translation type="unfinished">NiewystarczajÄ…ca pamięć podrÄ™czna bazy danych (dbcache) do weryfikacji bloków</translation> + </message> + <message> <source>Insufficient funds</source> <translation type="unfinished">NiewystarczajÄ…ce Å›rodki</translation> </message> @@ -4316,6 +4480,14 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">NieprawidÅ‚owe uprawnienia P2P: '%s'</translation> </message> <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">NieprawidÅ‚owa kwota dla %s=<amount>: '%s' (musi być co najmniej %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">NieprawidÅ‚owa kwota dla %s=<amount>: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished">NieprawidÅ‚owa kwota dla -%s=<amount>: '%s'</translation> </message> @@ -4324,6 +4496,14 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">NieprawidÅ‚owa maska sieci okreÅ›lona w -whitelist: '%s'</translation> </message> <message> + <source>Invalid port specified in %s: '%s'</source> + <translation type="unfinished">NieprawidÅ‚owa maska sieci okreÅ›lona w %s: '%s'</translation> + </message> + <message> + <source>Invalid pre-selected input %s</source> + <translation type="unfinished">Niepoprawne wstÄ™pnie wybrane dane wejÅ›ciowe %s</translation> + </message> + <message> <source>Loading P2P addresses…</source> <translation type="unfinished">Åadowanie adresów P2P...</translation> </message> @@ -4360,6 +4540,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Brak wystarczajÄ…cej liczby deskryptorów plików.</translation> </message> <message> + <source>Not found pre-selected input %s</source> + <translation type="unfinished">Nie znaleziono wstÄ™pnie wybranego wejÅ›cia %s</translation> + </message> + <message> <source>Prune cannot be configured with a negative value.</source> <translation type="unfinished">Przycinanie nie może być skonfigurowane z negatywnÄ… wartoÅ›ciÄ….</translation> </message> @@ -4425,6 +4609,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. </translation> </message> <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">OkreÅ›lony katalog danych "%s" nie istnieje</translation> + </message> + <message> <source>Starting network threads…</source> <translation type="unfinished">Startowanie wÄ…tków sieciowych...</translation> </message> @@ -4433,6 +4621,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Kod źródÅ‚owy dostÄ™pny jest z %s.</translation> </message> <message> + <source>The specified config file %s does not exist</source> + <translation type="unfinished">Podany plik konfiguracyjny %s nie istnieje</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation type="unfinished">Zbyt niska kwota transakcji by zapÅ‚acić opÅ‚atÄ™</translation> </message> @@ -4453,6 +4645,10 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">To jest opÅ‚ata transakcyjna którÄ… zapÅ‚acisz jeÅ›li wyÅ›lesz transakcjÄ™.</translation> </message> <message> + <source>Transaction %s does not belong to this wallet</source> + <translation type="unfinished">Transakcja %s nie należy do tego portfela</translation> + </message> + <message> <source>Transaction amount too small</source> <translation type="unfinished">Zbyt niska kwota transakcji</translation> </message> @@ -4541,10 +4737,30 @@ Przejdź do Plik > Otwórz Portfel aby wgrać portfel. <translation type="unfinished">Aktywowano nieznane nowe reguÅ‚y (versionbit %i)</translation> </message> <message> + <source>Unsupported global logging level %s=%s. Valid values: %s.</source> + <translation type="unfinished">Niewspierany globalny poziom logowania%s=%s. Poprawne wartoÅ›ci: %s.</translation> + </message> + <message> + <source>Wallet file creation failed: %s</source> + <translation type="unfinished">Utworzenie pliku portfela nie powiodÅ‚o siÄ™: %s</translation> + </message> + <message> + <source>acceptstalefeeestimates is not supported on %s chain.</source> + <translation type="unfinished">akceptowalne nieaktualne szacunki opÅ‚at nie sÄ… wspierane na Å‚aÅ„cuchu %s</translation> + </message> + <message> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished">NieobsÅ‚ugiwana kategoria rejestrowania %s=%s.</translation> </message> <message> + <source>Error: Could not add watchonly tx %s to watchonly wallet</source> + <translation type="unfinished">BÅ‚Ä…d: Nie można dodać tx %s tylko do odczytu do portfela tylko do odczytu</translation> + </message> + <message> + <source>Error: Could not delete watchonly transactions. </source> + <translation type="unfinished">BÅ‚Ä…d: Nie można usunąć transakcji tylko do odczytu.</translation> + </message> + <message> <source>User Agent comment (%s) contains unsafe characters.</source> <translation type="unfinished">Komentarz User Agent (%s) zawiera niebezpieczne znaki.</translation> </message> diff --git a/src/qt/locale/bitcoin_pt.ts b/src/qt/locale/bitcoin_pt.ts index 7de05fc230..c7975c0edf 100644 --- a/src/qt/locale/bitcoin_pt.ts +++ b/src/qt/locale/bitcoin_pt.ts @@ -7,7 +7,7 @@ </message> <message> <source>Create a new address</source> - <translation type="unfinished">Crie um endereço novo</translation> + <translation type="unfinished">Criar um novo endereço</translation> </message> <message> <source>&New</source> @@ -35,19 +35,19 @@ </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar os dados no separador atual para um ficheiro</translation> + <translation type="unfinished">Exportar os dados na aba atual para um ficheiro</translation> </message> <message> <source>&Export</source> - <translation type="unfinished">e exportar</translation> + <translation type="unfinished">&Exportar</translation> </message> <message> <source>&Delete</source> - <translation type="unfinished">&Eliminar</translation> + <translation type="unfinished">El&iminar</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation type="unfinished">Escolha o endereço para enviar as moedas</translation> + <translation type="unfinished">Escolha o endereço para onde enviar as moedas</translation> </message> <message> <source>Choose the address to receive coins with</source> @@ -59,21 +59,21 @@ </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">Estes são os seus endereços Bitcoin para enviar pagamentos. Verifique sempre o valor e o endereço de receção antes de enviar moedas.</translation> + <translation type="unfinished">Estes são os seus endereços Bitcoin para enviar pagamentos. Verifique sempre a quantia e o endereço de receção antes de enviar moedas.</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">Estes são seus novos endereços Bitcoin para o recebimento de pagamentos. Use o botão "Criar novo endereço de recebimento" na aba "Receber" para criar novos endereços. -Assinar só é possÃvel com endereços do tipo "legado".</translation> + <translation type="unfinished">Estes são os seus endereços Bitcoin para receber pagamentos. Utilize o botão "Criar novo endereço de receção" na aba "Receber" para criar novos endereços. +A assinatura só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>&Copy Address</source> - <translation type="unfinished">&Copiar Endereço</translation> + <translation type="unfinished">&Copiar endereço</translation> </message> <message> <source>Copy &Label</source> - <translation type="unfinished">Copiar &Etiqueta</translation> + <translation type="unfinished">Copiar &etiqueta</translation> </message> <message> <source>&Edit</source> @@ -81,7 +81,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Export Address List</source> - <translation type="unfinished">Exportar Lista de Endereços</translation> + <translation type="unfinished">Exportar lista de endereços</translation> </message> <message> <source>Comma separated file</source> @@ -91,19 +91,19 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <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">Ocorreu um erro ao tentar guardar a lista de endereços para %1. Por favor, tente novamente.</translation> + <translation type="unfinished">Ocorreu um erro ao tentar guardar a lista de endereços em %1. Por favor, tente novamente.</translation> </message> <message> <source>Sending addresses - %1</source> - <translation type="unfinished">Enviando endereços - %1</translation> + <translation type="unfinished">Endereço de envio - %1</translation> </message> <message> <source>Receiving addresses - %1</source> - <translation type="unfinished">Recebendo endereços - %1</translation> + <translation type="unfinished">Endereços de receção - %1</translation> </message> <message> <source>Exporting Failed</source> - <translation type="unfinished">Exportação Falhou</translation> + <translation type="unfinished">Falha na exportação</translation> </message> </context> <context> @@ -125,7 +125,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation type="unfinished">Janela da Frase de Segurança</translation> + <translation type="unfinished">Janela da frase de segurança</translation> </message> <message> <source>Enter passphrase</source> @@ -133,15 +133,15 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>New passphrase</source> - <translation type="unfinished">Nova frase de frase de segurança</translation> + <translation type="unfinished">Nova frase de segurança</translation> </message> <message> <source>Repeat new passphrase</source> - <translation type="unfinished">Repita a nova frase de frase de segurança</translation> + <translation type="unfinished">Repita a nova frase de segurança</translation> </message> <message> <source>Show passphrase</source> - <translation type="unfinished">Mostrar Password</translation> + <translation type="unfinished">Mostrar frase de segurança</translation> </message> <message> <source>Encrypt wallet</source> @@ -149,7 +149,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation type="unfinished">Esta operação precisa da sua frase de segurança da carteira para desbloquear a mesma.</translation> + <translation type="unfinished">Esta operação necessita da frase de segurança da sua carteira para a desbloquear.</translation> </message> <message> <source>Unlock wallet</source> @@ -177,15 +177,15 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation type="unfinished">Insira nova password para a carteira.<br/>Por favor use uma password de <b>dez ou mais caracteres</b>, ou <b>oito ou mais palavras</b>.</translation> + <translation type="unfinished">Insira a nova frase de segurança para a carteira.<br/>Por favor use uma frase de segurança de <b>dez ou mais caracteres</b> ou <b>oito ou mais palavras</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation type="unfinished">Insira a password antiga e a nova para a carteira.</translation> + <translation type="unfinished">Insira a frase de segurança antiga e a nova para a carteira.</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">Lembra se que encrostar a sua carteira não o pode defender na totalidade os seus bitcoins de serem roubados por um malware que possa infectar o seu computador.</translation> + <translation type="unfinished">Lembre-se que a encriptação da sua carteira não impede totalmente os seus bitcoins de serem roubados por programas maliciosos (malware) que infetem o seu computador.</translation> </message> <message> <source>Wallet to be encrypted</source> @@ -205,7 +205,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Wallet encryption failed</source> - <translation type="unfinished">Encriptação da carteira falhou</translation> + <translation type="unfinished">Falha na encriptação da carteira</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> @@ -217,7 +217,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Wallet unlock failed</source> - <translation type="unfinished">Desbloqueio da carteira falhou</translation> + <translation type="unfinished">Falha no desbloqueio da carteira</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> @@ -225,7 +225,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <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">A palavra passe inserida para a de-criptografia da carteira é incorreta . Ela contém um caractere nulo (ou seja - um byte zero). Se a palavra passe foi configurada em uma versão anterior deste software antes da versão 25.0, por favor tente novamente apenas com os caracteres maiúsculos — mas não incluindo — o primeiro caractere nulo. Se for bem-sucedido, defina uma nova senha para evitar esse problema no futuro.</translation> + <translation type="unfinished">A frase de segurança introduzida para a desencriptação da carteira está incorreta. Contém um carácter nulo (ou seja, um byte zero). Se a frase de segurança foi definida com uma versão deste software anterior à 25.0, tente novamente com apenas os caracteres até - mas não incluindo - o primeiro carácter nulo. Se isso for bem-sucedido, defina uma nova frase de segurança para evitar esse problema no futuro.</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> @@ -233,26 +233,26 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Passphrase change failed</source> - <translation type="unfinished">A alteração da frase de segurança falhou</translation> + <translation type="unfinished">Falha na alteração da frase de segurança</translation> </message> <message> <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">A senha antiga inserida para a de-criptografia da carteira está incorreta. Ele contém um caractere nulo (ou seja, um byte zero). Se a senha foi definida com uma versão deste software anterior a 25.0, tente novamente apenas com os caracteres maiúsculo — mas não incluindo — o primeiro caractere nulo.</translation> + <translation type="unfinished">A frase de segurança antiga introduzida para a desencriptação da carteira está incorreta. Contém um carácter nulo (ou seja, um byte zero). Se a frase de segurança foi definida com uma versão deste software anterior à 25.0, tente novamente com apenas os caracteres até - mas não incluindo - o primeiro carácter nulo.</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation type="unfinished">Aviso: a tecla Caps Lock está ativa!</translation> + <translation type="unfinished">Aviso: a tecla de bloqueio de maiúsculas está ativa!</translation> </message> </context> <context> <name>BanTableModel</name> <message> <source>IP/Netmask</source> - <translation type="unfinished">IP/Máscara de Rede</translation> + <translation type="unfinished">IP / máscara de rede</translation> </message> <message> <source>Banned Until</source> - <translation type="unfinished">Banido Até</translation> + <translation type="unfinished">Banido até</translation> </message> </context> <context> @@ -263,11 +263,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Runaway exception</source> - <translation type="unfinished">Exceção de Runaway</translation> + <translation type="unfinished">Exceção de fuga (runaway)</translation> </message> <message> <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> - <translation type="unfinished">Um erro fatal ocorreu. %1 não pode mais continuar de maneira segura e será terminada.</translation> + <translation type="unfinished">Ocorreu um erro fatal. %1 já não pode continuar em segurança e vai ser encerrado.</translation> </message> <message> <source>Internal error</source> @@ -288,7 +288,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</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">Ocorreu um erro fatal. Verifique se o arquivo de configurações é editável, ou tente correr com -nosettings.</translation> + <translation type="unfinished">Ocorreu um erro fatal. Verifique se o ficheiro de configurações pode ser escrito ou tente executar com -nosettings.</translation> </message> <message> <source>Error: %1</source> @@ -296,7 +296,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>%1 didn't yet exit safely…</source> - <translation type="unfinished">%1 ainda não terminou com segurança...</translation> + <translation type="unfinished">%1 ainda não encerrou de forma segura…</translation> </message> <message> <source>unknown</source> @@ -304,15 +304,15 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Embedded "%1"</source> - <translation type="unfinished">Embutido "%1"</translation> + <translation type="unfinished">"%1" embutido</translation> </message> <message> <source>Default system font "%1"</source> - <translation type="unfinished">Fonte padrão do sistema "%1"</translation> + <translation type="unfinished">Tipo de letra do sistema "%1"</translation> </message> <message> <source>Custom…</source> - <translation type="unfinished">Personalizado...</translation> + <translation type="unfinished">Personalizado…</translation> </message> <message> <source>Amount</source> @@ -344,17 +344,17 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <message> <source>Block Relay</source> <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment> - <translation type="unfinished">Retransmissão de Blocos</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> + <translation type="unfinished">Sensor</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> + <translation type="unfinished">Obtenção de endereços</translation> </message> <message> <source>None</source> @@ -431,7 +431,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>E&xit</source> - <translation type="unfinished">Fec&har</translation> + <translation type="unfinished">&Sair</translation> </message> <message> <source>Quit application</source> @@ -455,11 +455,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Modify configuration options for %1</source> - <translation type="unfinished">Modificar opções de configuração para %1</translation> + <translation type="unfinished">Alterar opções de configuração de %1</translation> </message> <message> <source>Create a new wallet</source> - <translation type="unfinished">Criar novo carteira</translation> + <translation type="unfinished">Criar nova carteira</translation> </message> <message> <source>&Minimize</source> @@ -476,7 +476,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> - <translation type="unfinished">Proxy está <b>ativado</b>: %1</translation> + <translation type="unfinished"> O proxy está <b>ativado</b>: %1</translation> </message> <message> <source>Send coins to a Bitcoin address</source> @@ -484,7 +484,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Backup wallet to another location</source> - <translation type="unfinished">Efetue uma cópia de segurança da carteira para outra localização</translation> + <translation type="unfinished">Fazer uma cópia de segurança da carteira para outra localização</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> @@ -504,7 +504,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>&Encrypt Wallet…</source> - <translation type="unfinished">Carteira &encriptada…</translation> + <translation type="unfinished">&Encriptar carteira…</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -532,11 +532,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation type="unfinished">Verifique mensagens para assegurar que foram assinadas com o endereço Bitcoin especificado</translation> + <translation type="unfinished">Verificar mensagens para garantir que foram assinadas com endereços Bitcoin especificados</translation> </message> <message> <source>&Load PSBT from file…</source> - <translation type="unfinished">&Carregar PSBT do arquivo...</translation> + <translation type="unfinished">&Carregar PSBT do ficheiro…</translation> </message> <message> <source>Open &URI…</source> @@ -568,11 +568,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Tabs toolbar</source> - <translation type="unfinished">Barra de ferramentas dos separadores</translation> + <translation type="unfinished">Barra de ferramentas das abas</translation> </message> <message> <source>Syncing Headers (%1%)…</source> - <translation type="unfinished">A sincronizar cabeçalhos (%1%)...</translation> + <translation type="unfinished">A sincronizar cabeçalhos (%1%)…</translation> </message> <message> <source>Synchronizing with network…</source> @@ -592,7 +592,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation type="unfinished">Solicitar pagamentos (gera códigos QR e bitcoin: URIs)</translation> + <translation type="unfinished">Pedir pagamentos (gera códigos QR e bitcoin: URIs)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> @@ -604,7 +604,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>&Command-line options</source> - <translation type="unfinished">&Opções da linha de &comando</translation> + <translation type="unfinished">Opções da linha de &comandos</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -615,11 +615,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>%1 behind</source> - <translation type="unfinished">%1 em atraso</translation> + <translation type="unfinished">%1 atrás</translation> </message> <message> <source>Catching up…</source> - <translation type="unfinished">Recuperando o atraso...</translation> + <translation type="unfinished">A recuperar o atraso…</translation> </message> <message> <source>Last received block was generated %1 ago.</source> @@ -627,7 +627,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation type="unfinished">As transações depois de isto ainda não serão visÃveis.</translation> + <translation type="unfinished">As transações posteriores a esta data ainda não serão visÃveis.</translation> </message> <message> <source>Error</source> @@ -651,7 +651,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Load PSBT from &clipboard…</source> - <translation type="unfinished">Carregar PSBT da área de transferência...</translation> + <translation type="unfinished">Carregar PSBT da área de transferência…</translation> </message> <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> @@ -663,23 +663,23 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation type="unfinished">Abrir o depurador de nó e o console de diagnóstico</translation> + <translation type="unfinished">Abrir a consola de diagnóstico e depuração de nó</translation> </message> <message> <source>&Sending addresses</source> - <translation type="unfinished">&Endereço de envio</translation> + <translation type="unfinished">&Endereços de envio</translation> </message> <message> <source>&Receiving addresses</source> - <translation type="unfinished">&Endereços de receção</translation> + <translation type="unfinished">Endereços de &receção</translation> </message> <message> <source>Open a bitcoin: URI</source> - <translation type="unfinished">Abrir um bitcoin URI</translation> + <translation type="unfinished">Abrir um bitcoin: URI</translation> </message> <message> <source>Open Wallet</source> - <translation type="unfinished">Abrir Carteira</translation> + <translation type="unfinished">Abrir carteira</translation> </message> <message> <source>Open a wallet</source> @@ -687,7 +687,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Close wallet</source> - <translation type="unfinished">Fechar a carteira</translation> + <translation type="unfinished">Fechar carteira</translation> </message> <message> <source>Restore Wallet…</source> @@ -701,7 +701,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Fechar todas carteiras.</translation> + <translation type="unfinished">Fechar todas carteiras</translation> </message> <message> <source>Migrate Wallet</source> @@ -713,15 +713,15 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation type="unfinished">Mostrar a mensagem de ajuda %1 para obter uma lista com possÃveis opções a usar na linha de comandos.</translation> + <translation type="unfinished">Mostrar a mensagem de ajuda %1 para obter uma lista com as possÃveis opções de linha de comandos do Bitcoin</translation> </message> <message> <source>&Mask values</source> - <translation type="unfinished">&Valores de Máscara</translation> + <translation type="unfinished">&Mascarar valores</translation> </message> <message> <source>Mask the values in the Overview tab</source> - <translation type="unfinished">Mascare os valores na aba de visão geral</translation> + <translation type="unfinished">Mascarar os valores na aba Resumo</translation> </message> <message> <source>default wallet</source> @@ -739,7 +739,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <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> + <translation type="unfinished">Carregar cópia de segurança da carteira</translation> </message> <message> <source>Restore Wallet</source> @@ -749,7 +749,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <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> + <translation type="unfinished">Nome da carteira</translation> </message> <message> <source>&Window</source> @@ -769,7 +769,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>&Hide</source> - <translation type="unfinished">Ocultar</translation> + <translation type="unfinished">&Ocultar</translation> </message> <message> <source>S&how</source> @@ -779,19 +779,19 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"> - <numerusform>%n conexão ativa na rede Bitcoin.</numerusform> - <numerusform>%n conexões ativas na rede Bitcoin.</numerusform> + <numerusform>%n conexão ativa com a rede Bitcoin.</numerusform> + <numerusform>%n conexões ativas com a rede 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">Clique para mais acções.</translation> + <translation type="unfinished">Clique para mais ações.</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">Mostra aba de Pares</translation> + <translation type="unfinished">Mostra aba Pares</translation> </message> <message> <source>Disable network activity</source> @@ -801,7 +801,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <message> <source>Enable network activity</source> <extracomment>A context menu item. The network activity was disabled previously.</extracomment> - <translation type="unfinished">Activar atividade da rede</translation> + <translation type="unfinished">Ativar atividade da rede</translation> </message> <message> <source>Pre-syncing Headers (%1%)…</source> @@ -832,7 +832,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <message> <source>Amount: %1 </source> - <translation type="unfinished">Valor: %1 + <translation type="unfinished">Quantia: %1 </translation> </message> <message> @@ -869,11 +869,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation type="unfinished">Criação de chave HD está <b>ativada</b></translation> + <translation type="unfinished">A criação de chave HD está <b>ativada</b></translation> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation type="unfinished">Criação de chave HD está <b>desativada</b></translation> + <translation type="unfinished">A criação de chave HD está <b>desativada</b></translation> </message> <message> <source>Private key <b>disabled</b></source> @@ -896,14 +896,14 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <name>UnitDisplayStatusBarControl</name> <message> <source>Unit to show amounts in. Click to select another unit.</source> - <translation type="unfinished">Unidade de valores recebidos. Clique para selecionar outra unidade.</translation> + <translation type="unfinished">Unidade de quantias recebidas. Clique para selecionar outra unidade.</translation> </message> </context> <context> <name>CoinControlDialog</name> <message> <source>Coin Selection</source> - <translation type="unfinished">Seleção de Moeda</translation> + <translation type="unfinished">Seleção de moeda</translation> </message> <message> <source>Quantity:</source> @@ -919,7 +919,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>After Fee:</source> - <translation type="unfinished">Depois da taxa:</translation> + <translation type="unfinished">Após a taxa:</translation> </message> <message> <source>Change:</source> @@ -927,7 +927,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>(un)select all</source> - <translation type="unfinished">(des)selecionar todos</translation> + <translation type="unfinished">(des)selecionar tudo</translation> </message> <message> <source>Tree mode</source> @@ -959,11 +959,11 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmada</translation> + <translation type="unfinished">Confirmado</translation> </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar valor</translation> + <translation type="unfinished">Copiar quantia</translation> </message> <message> <source>&Copy address</source> @@ -979,7 +979,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Copy transaction &ID and output index</source> - <translation type="unfinished">Copiar &ID da transação e index do output</translation> + <translation type="unfinished">Copiar o &ID da transação e o Ãndice de saÃda</translation> </message> <message> <source>L&ock unspent</source> @@ -999,7 +999,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar depois da taxa</translation> + <translation type="unfinished">Copiar após a taxa</translation> </message> <message> <source>Copy bytes</source> @@ -1015,7 +1015,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation type="unfinished">Pode variar +/- %1 satoshi(s) por input.</translation> + <translation type="unfinished">Pode variar +/- %1 satoshi(s) por entrada.</translation> </message> <message> <source>(no label)</source> @@ -1035,7 +1035,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <message> <source>Create Wallet</source> <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment> - <translation type="unfinished">Criar Carteira</translation> + <translation type="unfinished">Criar carteira</translation> </message> <message> <source>Creating Wallet <b>%1</b>…</source> @@ -1052,7 +1052,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> </message> <message> <source>Can't list signers</source> - <translation type="unfinished">Não é possÃvel listar signatários</translation> + <translation type="unfinished">Não é possÃvel listar os signatários</translation> </message> <message> <source>Too many external signers found</source> @@ -1069,7 +1069,7 @@ Assinar só é possÃvel com endereços do tipo "legado".</translation> <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">A carregar carteiras...</translation> + <translation type="unfinished">A carregar carteiras…</translation> </message> </context> <context> @@ -1088,11 +1088,11 @@ If this wallet contains any watchonly scripts, a new wallet will be created whic If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts. The migration process will create a backup of the wallet before migrating. This backup file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of an incorrect migration, the backup can be restored with the "Restore Wallet" functionality.</source> - <translation type="unfinished">A migração irá converter esta carteira em uma ou mais carteiras com descritores. Será necessário realizar um novo backup da carteira. -Se esta carteira contiver scripts watchonly, uma carteira nova será criada contendo estes scripts watchonly. -Se esta carteira contiver algum script solucionável, mas não monitorado, uma carteira nova e diferente será criada contendo esses scripts. + <translation type="unfinished">A migração da carteira converterá esta carteira numa ou mais carteiras descritoras. Terá de ser efetuada uma nova cópia de segurança da carteira. +Se esta carteira contiver quaisquer scripts só de observação, será criada uma nova carteira que contenha esses scripts só de observação. +Se esta carteira contiver quaisquer scripts solucionáveis mas não observados, será criada uma carteira nova e diferente que contenha esses scripts. -O processo de migração criará um backup da carteira antes da migração. Este arquivo de backup será nomeado <wallet name>-<timestamp>.legacy.bak e pode ser encontrado no diretório desta carteira. No caso de uma migração incorreta, o backup pode ser restaurado com a funcionalidade “Restaurar Carteiraâ€.</translation> +O processo de migração criará uma cópia de segurança da carteira antes da migração. Este ficheiro de cópia de segurança será denominado <wallet name>-<timestamp>.legacy.bak e pode ser encontrado no diretório para esta carteira. Na eventualidade de uma migração incorreta, a cópia de segurança pode ser restaurada com a funcionalidade "Restaurar carteira".</translation> </message> <message> <source>Migrate Wallet</source> @@ -1100,15 +1100,19 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Migrating Wallet <b>%1</b>…</source> - <translation type="unfinished">Migrando Carteira <b>%1</b>…</translation> + <translation type="unfinished">A migrar a carteira <b>%1</b>…</translation> </message> <message> <source>The wallet '%1' was migrated successfully.</source> <translation type="unfinished">A carteira '%1' foi migrada com sucesso.</translation> </message> <message> + <source>Watchonly scripts have been migrated to a new wallet named '%1'.</source> + <translation type="unfinished">Os scripts de observação/watchonly foram migrados para uma nova carteira chamada '%1'.</translation> + </message> + <message> <source>Solvable but not watched scripts have been migrated to a new wallet named '%1'.</source> - <translation type="unfinished">Os guiões solucionáveis mas não observados foram migrados para uma nova pasta chamada '%1'.</translation> + <translation type="unfinished">Os scripts solucionáveis mas não observados/watched foram migrados para uma nova carteira chamada '%1'.</translation> </message> <message> <source>Migration failed</source> @@ -1127,7 +1131,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Open wallet warning</source> - <translation type="unfinished">Aviso abertura carteira</translation> + <translation type="unfinished">Aviso de carteira aberta</translation> </message> <message> <source>default wallet</source> @@ -1136,7 +1140,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <message> <source>Open Wallet</source> <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> - <translation type="unfinished">Abrir Carteira</translation> + <translation type="unfinished">Abrir carteira</translation> </message> <message> <source>Opening Wallet <b>%1</b>…</source> @@ -1164,7 +1168,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <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> + <translation type="unfinished">Aviso de restaurar a carteira</translation> </message> <message> <source>Restore wallet message</source> @@ -1176,34 +1180,34 @@ O processo de migração criará um backup da carteira antes da migração. Este <name>WalletController</name> <message> <source>Close wallet</source> - <translation type="unfinished">Fechar a carteira</translation> + <translation type="unfinished">Fechar carteira</translation> </message> <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation type="unfinished">Tem a certeza que deseja fechar esta carteira <i>%1</i>?</translation> + <translation type="unfinished">Tem a certeza que deseja fechar a carteira <i>%1</i>?</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">Fechar a carteira durante demasiado tempo pode resultar em ter de resincronizar a cadeia inteira se pruning estiver ativado.</translation> + <translation type="unfinished">Fechar a carteira durante demasiado tempo pode resultar na necessidade de voltar a sincronizar toda a cadeia se a redução (prune) estiver ativada.</translation> </message> <message> <source>Close all wallets</source> - <translation type="unfinished">Fechar todas carteiras.</translation> + <translation type="unfinished">Fechar todas carteiras</translation> </message> <message> <source>Are you sure you wish to close all wallets?</source> - <translation type="unfinished">Você tem certeza que deseja fechar todas as carteira?</translation> + <translation type="unfinished">Tem a certeza de que deseja fechar todas as carteiras?</translation> </message> </context> <context> <name>CreateWalletDialog</name> <message> <source>Create Wallet</source> - <translation type="unfinished">Criar Carteira</translation> + <translation type="unfinished">Criar carteira</translation> </message> <message> <source>You are one step away from creating your new wallet!</source> - <translation type="unfinished">Você está a um passo de criar a sua nova carteira!</translation> + <translation type="unfinished">Está a um passo de criar a sua nova carteira!</translation> </message> <message> <source>Please provide a name and, if desired, enable any advanced options</source> @@ -1211,7 +1215,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Wallet Name</source> - <translation type="unfinished">Nome da Carteira</translation> + <translation type="unfinished">Nome da carteira</translation> </message> <message> <source>Wallet</source> @@ -1219,11 +1223,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation type="unfinished">Encriptar carteira. A carteira vai ser encriptada com uma password de sua escolha.</translation> + <translation type="unfinished">Encriptar carteira. A carteira vai ser encriptada com uma frase de segurança à sua escolha.</translation> </message> <message> <source>Encrypt Wallet</source> - <translation type="unfinished">Encriptar Carteira</translation> + <translation type="unfinished">Encriptar carteira</translation> </message> <message> <source>Advanced Options</source> @@ -1231,19 +1235,19 @@ O processo de migração criará um backup da carteira antes da migração. Este </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">Desative chaves privadas para esta carteira. As carteiras com chaves privadas desativadas não terão chaves privadas e não poderão ter uma semente em HD ou chaves privadas importadas. Isso é ideal para carteiras sem movimentos.</translation> + <translation type="unfinished">Desativar as chaves privadas para esta carteira. As carteiras com chaves privadas desativadas não terão chaves privadas e não podem ter uma semente HD ou chaves privadas importadas. Isto é ideal para carteiras só de observação.</translation> </message> <message> <source>Disable Private Keys</source> - <translation type="unfinished">Desactivar Chaves Privadas</translation> + <translation type="unfinished">Desativar chaves 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">Faça uma carteira em branco. As carteiras em branco não possuem inicialmente chaves ou scripts privados. Chaves e endereços privados podem ser importados ou uma semente HD pode ser configurada posteriormente.</translation> + <translation type="unfinished">Crie uma carteira em branco. As carteiras em branco não têm inicialmente chaves privadas ou scripts. As chaves privadas e os endereços podem ser importados ou pode ser definida uma semente HD numa altura posterior.</translation> </message> <message> <source>Make Blank Wallet</source> - <translation type="unfinished">Fazer Carteira em Branco</translation> + <translation type="unfinished">Criar uma carteira em branco</translation> </message> <message> <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source> @@ -1251,7 +1255,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>External signer</source> - <translation type="unfinished">Signatário externo</translation> + <translation type="unfinished">Assinante externo</translation> </message> <message> <source>Create</source> @@ -1260,14 +1264,14 @@ O processo de migração criará um backup da carteira antes da migração. Este <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 sem suporte de assinatura externa. (necessário para assinatura externa)</translation> + <translation type="unfinished">Compilado sem suporte de assinatura externa (necessário para assinatura externa)</translation> </message> </context> <context> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation type="unfinished">Editar Endereço</translation> + <translation type="unfinished">Editar endereço</translation> </message> <message> <source>&Label</source> @@ -1275,11 +1279,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>The label associated with this address list entry</source> - <translation type="unfinished">A etiqueta associada com esta entrada da lista de endereços</translation> + <translation type="unfinished">A etiqueta associada a esta entrada da lista de endereços</translation> </message> <message> <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> - <translation type="unfinished">O endereço associado com o esta entrada da lista de endereços. Isto só pode ser alterado para os endereços de envio.</translation> + <translation type="unfinished">O endereço associado a esta entrada da lista de endereços. Isto só pode ser alterado para os endereços de envio.</translation> </message> <message> <source>&Address</source> @@ -1295,7 +1299,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Edit sending address</source> - <translation type="unfinished">Editar o endereço de envio</translation> + <translation type="unfinished">Editar endereço de envio</translation> </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> @@ -1366,22 +1370,22 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Choose data directory</source> - <translation type="unfinished">Escolha o diretório dos dados</translation> + <translation type="unfinished">Escolha a pasta dos dados</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">No mÃnimo %1 GB de dados irão ser armazenados nesta pasta.</translation> + <translation type="unfinished">Serão armazenados nesta pasta pelo menos %1 GB de dados, que irão aumentar com o tempo.</translation> </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation type="unfinished">Aproximadamente %1 GB de dados irão ser guardados nesta pasta.</translation> + <translation type="unfinished">Serão guardados nesta pasta aproximadamente %1 GB de dados.</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>(suficiente para restaurar backups de %n dia atrás)</numerusform> - <numerusform>(suficiente para restaurar backups de %n dias atrás)</numerusform> + <numerusform>(suficiente para restaurar cópias de segurança de %n dia atrás)</numerusform> + <numerusform>(suficiente para restaurar cópias de segurança de %n dias atrás)</numerusform> </translation> </message> <message> @@ -1394,7 +1398,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> - <translation type="unfinished">Erro: não pode ser criada a pasta de dados especificada como "%1.</translation> + <translation type="unfinished">Erro: não pode ser criada a pasta de dados especificada como "%1".</translation> </message> <message> <source>Error</source> @@ -1414,23 +1418,23 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Limit block chain storage to</source> - <translation type="unfinished">Limitar o tamanho da blockchain para</translation> + <translation type="unfinished">Limitar o armazenamento da cadeia de blocos 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">Para reverter essa configuração, é necessário o download de todo o blockchain novamente. É mais rápido fazer o download da blockchain completa primeiro e removê-la mais tarde. Desativa alguns recursos avançados.</translation> + <translation type="unfinished">Se reverter esta configuração terá de descarregar novamente toda a cadeia de blocos. É mais rápido fazer o descarregamento da cadeia completa primeiro e reduzi-la (prune) mais tarde. Isto desativa alguns recursos avançados.</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 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> + <translation type="unfinished">Esta sincronização inicial é muito exigente e pode expor problemas de hardware no seu computador que anteriormente tinham passado despercebidos. Sempre que executar o %1, este continuará a descarregar a partir do ponto em que foi interrompido.</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> + <translation type="unfinished">Quando clicar em OK, %1 começará a descarregar e a processar toda a cadeia de blocos de %4 (%2 GB), começando com as primeiras transações em %3 quando %4 foi lançado 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">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> + <translation type="unfinished">Se tiver optado por reduzir o armazenamento da cadeia de blocos (prune), os dados históricos ainda têm de ser descarregados e processados, mas serão eliminados posteriormente para manter a utilização do disco baixa.</translation> </message> <message> <source>Use the default data directory</source> @@ -1453,14 +1457,14 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Command-line options</source> - <translation type="unfinished">Opções da linha de comando</translation> + <translation type="unfinished">Opções da linha de comandos</translation> </message> </context> <context> <name>ShutdownWindow</name> <message> <source>%1 is shutting down…</source> - <translation type="unfinished">%1 está a desligar…</translation> + <translation type="unfinished">%1 está a encerrar…</translation> </message> <message> <source>Do not shut down the computer until this window disappears.</source> @@ -1475,11 +1479,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </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">Transações recentes podem não ser visÃveis por agora, portanto o saldo da sua carteira pode estar incorreto. Esta informação será corrigida quando a sua carteira acabar de sincronizar com a rede, como está explicado em baixo.</translation> + <translation type="unfinished">As transações recentes podem ainda não ser visÃveis e, por isso, o saldo da sua carteira pode estar incorreto. Esta informação estará correta assim que a sua carteira terminar a sincronização com a rede bitcoin, conforme detalhado abaixo.</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">Tentar enviar bitcoins que estão afetadas por transações ainda não exibidas não será aceite pela rede.</translation> + <translation type="unfinished">A rede não aceitará tentativas de gastar bitcoins afetados por transações que ainda não foram mostradas.</translation> </message> <message> <source>Number of blocks left</source> @@ -1503,43 +1507,39 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Progress increase per hour</source> - <translation type="unfinished">Aumento horário do progresso</translation> + <translation type="unfinished">Aumento do progresso por hora</translation> </message> <message> <source>Estimated time left until synced</source> - <translation type="unfinished">tempo restante estimado até à sincronização</translation> + <translation type="unfinished">Tempo estimado até à sincronização</translation> </message> <message> <source>Hide</source> <translation type="unfinished">Ocultar</translation> </message> <message> - <source>Esc</source> - <translation type="unfinished">Sair</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á neste momento a sincronizar. Irá descarregar os cabeçalhos e blocos dos pares e validá-los até atingir a ponta da cadeia de blocos.</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)…</source> - <translation type="unfinished">Desconhecido. A sincronizar cabeçalhos (%1, %2%)...</translation> + <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> + <translation type="unfinished">Desconhecido. A pré-sincronizar cabeçalhos (%1, %2%)…</translation> </message> </context> <context> <name>OpenURIDialog</name> <message> <source>Open bitcoin URI</source> - <translation type="unfinished">Abrir um Bitcoin URI</translation> + <translation type="unfinished">Abrir um 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">Cole endereço da área de transferência</translation> + <translation type="unfinished">Colar endereço da área de transferência</translation> </message> </context> <context> @@ -1562,7 +1562,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </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">A ativação do pruning reduz significativamente o espaço em disco necessário para armazenar transações. Todos os blocos ainda estão totalmente validados. Reverter esta configuração requer que faça novamente o download de toda a blockchain.</translation> + <translation type="unfinished">A ativação da poda reduz significativamente o espaço em disco necessário para armazenar transações. Todos os blocos continuam a ser totalmente validados. Reverter esta configuração requer fazer o descarregamento de toda a cadeia de blocos.</translation> </message> <message> <source>Size of &database cache</source> @@ -1573,40 +1573,44 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Número de processos de &verificação de scripts</translation> </message> <message> + <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">Caminho completo para um script compatÃvel %1 (exemplo C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Cuidado: um programa malicioso (malware) pode roubar as suas moedas!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">Endereço de IP do proxy (exemplo, 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">Mostra se o padrão fornecido SOCKS5 proxy, está a ser utilizado para alcançar utilizadores participantes através deste tipo de rede.</translation> + <translation type="unfinished">Mostra se o proxy SOCKS5 padrão fornecido é usado para alcançar os pares através deste tipo de rede.</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 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> + <translation type="unfinished">Minimizar em vez de sair da aplicação quando a janela é fechada. Quando esta opção é ativada, a aplicação apenas será encerrada quando selecionar "Sair" no menu.</translation> </message> <message> <source>Font in the Overview tab: </source> - <translation type="unfinished">Fonte no painel de visualização:</translation> + <translation type="unfinished">Tipo de letra na aba Resumo:</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> + <translation type="unfinished">As opções definidas nesta caixa de diálogo são substituÃdas pela linha de comandos:</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> + <translation type="unfinished">Abrir o ficheiro de configuração %1 a partir da pasta de trabalho.</translation> </message> <message> <source>Open Configuration File</source> - <translation type="unfinished">Abrir Ficheiro de Configuração</translation> + <translation type="unfinished">Abrir ficheiro de configuração</translation> </message> <message> <source>Reset all client options to default.</source> - <translation type="unfinished">Repor todas as opções de cliente para a predefinição.</translation> + <translation type="unfinished">Repor todas as opções do cliente para os valores de origem.</translation> </message> <message> <source>&Reset Options</source> - <translation type="unfinished">&Repor Opções</translation> + <translation type="unfinished">&Repor opções</translation> </message> <message> <source>&Network</source> @@ -1617,26 +1621,22 @@ O processo de migração criará um backup da carteira antes da migração. Este <translation type="unfinished">Reduzir o armazenamento de &bloco para</translation> </message> <message> - <source>GB</source> - <translation type="unfinished">PT</translation> - </message> - <message> <source>Reverting this setting requires re-downloading the entire blockchain.</source> - <translation type="unfinished">Reverter esta configuração requer descarregar de novo a cadeia de blocos inteira.</translation> + <translation type="unfinished">Se reverter esta configuração terá de descarregar novamente toda a cadeia de blocos.</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 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> + <translation type="unfinished">Tamanho máximo da cache da base de dados. Uma cache maior pode contribuir para uma sincronização mais rápida, da qual os benefÃcios são menos visÃveis. Diminuir o tamanho da cache reduzirá a utilização de memória. A memória mempool não utilizada 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> + <translation type="unfinished">Define o número de sub-processos (threads) de verificação de scripts. Os valores negativos correspondem ao número de núcleos que pretende deixar livres para o sistema.</translation> </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation type="unfinished">(0 = automático, <0 = deixar essa quantidade de núcleos livre)</translation> + <translation type="unfinished">(0 = automático, <0 = deixar este número de núcleos 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> @@ -1655,7 +1655,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <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> + <translation type="unfinished">Se deve ser mostrado por padrão a quantia com a taxa já subtraÃda.</translation> </message> <message> <source>Subtract &fee from amount by default</source> @@ -1686,19 +1686,19 @@ O processo de migração criará um backup da carteira antes da migração. Este <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> + <translation type="unfinished">Se devem ser mostrados 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> + <translation type="unfinished">Assinante externo (por exemplo, carteira de hardware)</translation> </message> <message> <source>&External signer script path</source> - <translation type="unfinished">&Caminho do script para signatário externo </translation> + <translation type="unfinished">&Caminho do script para assinante externo</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 a porta do cliente bitcoin automaticamente no seu router. Isto apenas funciona se o seu router suportar UPnP e este se encontrar ligado.</translation> + <translation type="unfinished">Abrir automaticamente a porta do cliente Bitcoin no seu router. Isto só funciona quando o seu router suporta UPnP e este está ativado.</translation> </message> <message> <source>Map port using &UPnP</source> @@ -1706,7 +1706,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </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> + <translation type="unfinished">Abrir automaticamente a porta do cliente Bitcoin no seu router. Isto só funciona quando o seu router suporta NAT-PMP e este está ativado. A porta externa pode ser aleatória.</translation> </message> <message> <source>Map port using NA&T-PMP</source> @@ -1714,11 +1714,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Accept connections from outside.</source> - <translation type="unfinished">Aceitar ligações externas.</translation> + <translation type="unfinished">Aceitar conexões do exterior.</translation> </message> <message> <source>Allow incomin&g connections</source> - <translation type="unfinished">Permitir ligações de "a receber"</translation> + <translation type="unfinished">Permitir cone&xões de entrada</translation> </message> <message> <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> @@ -1726,7 +1726,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>&Connect through SOCKS5 proxy (default proxy):</source> - <translation type="unfinished">&Ligar através dum proxy SOCKS5 (proxy por defeito):</translation> + <translation type="unfinished">&Conectar através de um proxy SOCKS5 (proxy padrão):</translation> </message> <message> <source>Proxy &IP:</source> @@ -1754,7 +1754,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>&Show tray icon</source> - <translation type="unfinished">&Mostrar Ãcone de bandeja</translation> + <translation type="unfinished">&Mostrar Ãcone da bandeja</translation> </message> <message> <source>Show only a tray icon after minimizing the window.</source> @@ -1774,11 +1774,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>User Interface &language:</source> - <translation type="unfinished">&Linguagem da interface de utilizador:</translation> + <translation type="unfinished">&Idioma da interface:</translation> </message> <message> <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> - <translation type="unfinished">A linguagem da interface do utilizador pode ser definida aqui. Esta definição entrará em efeito após reiniciar %1.</translation> + <translation type="unfinished">O idioma da interface do utilizador pode ser definido aqui. Esta definição entra em vigor depois de reiniciar %1.</translation> </message> <message> <source>&Unit to show amounts in:</source> @@ -1790,7 +1790,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </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> + <translation type="unfinished">URLs de terceiros (por exemplo, um explorador de blocos) que aparecem na aba de transações como itens de menu de contexto. %s no URL é substituÃdo pelo hash da transação. Vários URLs são separados por barras verticais |.</translation> </message> <message> <source>&Third-party transaction URLs</source> @@ -1802,11 +1802,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> - <translation type="unfinished">Conecte-se a rede Bitcoin através de um proxy SOCKS5 separado para serviços Tor Onion</translation> + <translation type="unfinished">Conecte-se à rede Bitcoin através de um proxy SOCKS5 separado para serviços Tor Onion</translation> </message> <message> <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> - <translation type="unfinished">Use um proxy SOCKS5 separado para alcançar pares por meio dos serviços Tor onion:</translation> + <translation type="unfinished">Utilizar um proxy SOCKS5 separado para aceder aos pares através dos serviços Tor onion:</translation> </message> <message> <source>&Cancel</source> @@ -1815,7 +1815,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <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 sem suporte de assinatura externa. (necessário para assinatura externa)</translation> + <translation type="unfinished">Compilado sem suporte de assinatura externa (necessário para assinatura externa)</translation> </message> <message> <source>default</source> @@ -1838,22 +1838,22 @@ O processo de migração criará um backup da carteira antes da migração. Este <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> + <translation type="unfinished">As definições atuais serão guardadas 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> + <translation type="unfinished">O cliente será encerrado. Quer continuar?</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">Opções da configuração</translation> + <translation type="unfinished">Opções de configuração</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">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> + <translation type="unfinished">O ficheiro de configuração é utilizado para especificar opções avançadas do utilizador que se sobrepõem à s definições da GUI. Além disso, quaisquer opções da linha de comandos substituirão este ficheiro de configuração.</translation> </message> <message> <source>Continue</source> @@ -1873,7 +1873,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>This change would require a client restart.</source> - <translation type="unfinished">Esta alteração obrigará a um reinÃcio do cliente.</translation> + <translation type="unfinished">Esta alteração requer que o cliente seja reiniciado.</translation> </message> <message> <source>The supplied proxy address is invalid.</source> @@ -1884,7 +1884,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <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> + <translation type="unfinished">Não foi possÃvel ler a configuração "%1", %2.</translation> </message> </context> <context> @@ -1895,11 +1895,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </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">A informação mostrada poderá estar desatualizada. A sua carteira sincroniza automaticamente com a rede Bitcoin depois de estabelecer ligação, mas este processo ainda não está completo.</translation> + <translation type="unfinished">A informação apresentada pode estar desatualizada. A sua carteira sincroniza-se automaticamente com a rede Bitcoin após o estabelecimento de conexões, mas este processo ainda não está concluÃdo.</translation> </message> <message> <source>Watch-only:</source> - <translation type="unfinished">Apenas vigiar:</translation> + <translation type="unfinished">Apenas observação:</translation> </message> <message> <source>Available:</source> @@ -1923,7 +1923,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Mined balance that has not yet matured</source> - <translation type="unfinished">O saldo minado ainda não amadureceu</translation> + <translation type="unfinished">Saldo minerado que ainda não atingiu a maturidade</translation> </message> <message> <source>Balances</source> @@ -1935,31 +1935,31 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Your current balance in watch-only addresses</source> - <translation type="unfinished">O seu balanço atual em endereços de apenas vigiar</translation> + <translation type="unfinished">O seu saldo atual em endereços de observação</translation> </message> <message> <source>Spendable:</source> - <translation type="unfinished">Dispensável:</translation> + <translation type="unfinished">Gastável:</translation> </message> <message> <source>Recent transactions</source> - <translation type="unfinished">transações recentes</translation> + <translation type="unfinished">Transações recentes</translation> </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation type="unfinished">Transações não confirmadas para endereços de apenas vigiar</translation> + <translation type="unfinished">Transações não confirmadas para endereços de observação</translation> </message> <message> <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation type="unfinished">Saldo minado ainda não disponÃvel de endereços de apenas vigiar</translation> + <translation type="unfinished">Saldo minerado em endereços só de observação que ainda não atingiram a maturidade</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation type="unfinished">Saldo disponÃvel em endereços de apenas vigiar</translation> + <translation type="unfinished">Saldo disponÃvel em endereços de observação</translation> </message> <message> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> - <translation type="unfinished">Modo de privacidade ativado para a aba de visão geral. para desmascarar os valores, desmarque nas Configurações -> Valores de máscara</translation> + <translation type="unfinished">Modo de privacidade ativado para a aba Resumo. para desmascarar os valores, desmarque nas Configurações -> Valores de máscara</translation> </message> </context> <context> @@ -1990,15 +1990,15 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Failed to load transaction: %1</source> - <translation type="unfinished">Falha ao carregar transação: %1</translation> + <translation type="unfinished">Falha ao carregar a transação: %1</translation> </message> <message> <source>Failed to sign transaction: %1</source> - <translation type="unfinished">Falha ao assinar transação: %1</translation> + <translation type="unfinished">Falha ao assinar a 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> + <translation type="unfinished">Não é possÃvel assinar entradas enquanto a carteira estiver bloqueada.</translation> </message> <message> <source>Could not sign any more inputs.</source> @@ -2006,11 +2006,11 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Signed %1 inputs, but more signatures are still required.</source> - <translation type="unfinished">Assinadas entradas %1, mas mais assinaturas ainda são necessárias.</translation> + <translation type="unfinished">%1 entradas assinadas, mas ainda são necessárias mais assinaturas.</translation> </message> <message> <source>Signed transaction successfully. Transaction is ready to broadcast.</source> - <translation type="unfinished">Transação assinada com sucesso. Transação está pronta para ser transmitida.</translation> + <translation type="unfinished">Transação assinada com sucesso. A transação está pronta para ser transmitida.</translation> </message> <message> <source>Unknown error processing transaction.</source> @@ -2019,7 +2019,7 @@ O processo de migração criará um backup da carteira antes da migração. Este <message> <source>Transaction broadcast successfully! Transaction ID: %1</source> <translation type="unfinished">Transação transmitida com sucesso. -ID transação: %1</translation> +ID da transação: %1</translation> </message> <message> <source>Transaction broadcast failed: %1</source> @@ -2031,16 +2031,16 @@ ID transação: %1</translation> </message> <message> <source>Save Transaction Data</source> - <translation type="unfinished">Salvar informação de transação</translation> + <translation type="unfinished">Guardar informação da transação</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">Transação parcialmente assinada (Binário)</translation> + <translation type="unfinished">Transação parcialmente assinada (binário)</translation> </message> <message> <source>PSBT saved to disk.</source> - <translation type="unfinished">PSBT salva no disco.</translation> + <translation type="unfinished">PSBT guardada no disco.</translation> </message> <message> <source>Sends %1 to %2</source> @@ -2048,11 +2048,11 @@ ID transação: %1</translation> </message> <message> <source>own address</source> - <translation type="unfinished">endereço próprio</translation> + <translation type="unfinished">próprio endereço</translation> </message> <message> <source>Unable to calculate transaction fee or total transaction amount.</source> - <translation type="unfinished">Incapaz de calcular a taxa de transação ou o valor total da transação.</translation> + <translation type="unfinished">Não foi possÃvel calcular a taxa de transação ou a quantia total da transação.</translation> </message> <message> <source>Pays transaction fee: </source> @@ -2060,7 +2060,7 @@ ID transação: %1</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Valor Total</translation> + <translation type="unfinished">Quantia total</translation> </message> <message> <source>or</source> @@ -2068,15 +2068,15 @@ ID transação: %1</translation> </message> <message> <source>Transaction has %1 unsigned inputs.</source> - <translation type="unfinished">Transação tem %1 entradas não assinadas.</translation> + <translation type="unfinished">A transação tem %1 entradas não assinadas.</translation> </message> <message> <source>Transaction is missing some information about inputs.</source> - <translation type="unfinished">Transação está com alguma informação faltando sobre as entradas.</translation> + <translation type="unfinished">A transação não contém algumas informações sobre as entradas.</translation> </message> <message> <source>Transaction still needs signature(s).</source> - <translation type="unfinished">Transação continua precisando de assinatura(s).</translation> + <translation type="unfinished">A transação ainda precisa de assinatura(s).</translation> </message> <message> <source>(But no wallet is loaded.)</source> @@ -2092,11 +2092,11 @@ ID transação: %1</translation> </message> <message> <source>Transaction is fully signed and ready for broadcast.</source> - <translation type="unfinished">Transação está completamente assinada e pronta para ser transmitida.</translation> + <translation type="unfinished">A transação está totalmente assinada e pronta para ser transmitida.</translation> </message> <message> <source>Transaction status is unknown.</source> - <translation type="unfinished">Status da transação é desconhecido.</translation> + <translation type="unfinished">O estado da transação é desconhecido.</translation> </message> </context> <context> @@ -2107,7 +2107,7 @@ ID transação: %1</translation> </message> <message> <source>Cannot start bitcoin: click-to-pay handler</source> - <translation type="unfinished">ImpossÃvel iniciar o controlador de bitcoin: click-to-pay</translation> + <translation type="unfinished">Não é possÃvel iniciar o bitcoin: manipulador do click-to-pay</translation> </message> <message> <source>URI handling</source> @@ -2122,21 +2122,26 @@ ID transação: %1</translation> 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. +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> + <translation type="unfinished">O URI não pode ser analisado! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation> </message> <message> <source>Payment request file handling</source> - <translation type="unfinished">Controlo de pedidos de pagamento.</translation> + <translation type="unfinished">Manuseamento do ficheiro de pedidos de pagamento.</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 do utilizador</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">Latência</translation> @@ -2149,7 +2154,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <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> + <translation type="unfinished">Idade</translation> </message> <message> <source>Direction</source> @@ -2200,7 +2205,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>&Copy Image</source> - <translation type="unfinished">&Copiar Imagem</translation> + <translation type="unfinished">&Copiar imagem</translation> </message> <message> <source>Resulting URI too long, try to reduce the text for label / message.</source> @@ -2208,15 +2213,15 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Error encoding URI into QR Code.</source> - <translation type="unfinished">Erro ao codificar URI em Código QR.</translation> + <translation type="unfinished">Erro ao codificar URI em código QR.</translation> </message> <message> <source>QR code support not available.</source> - <translation type="unfinished">Suporte códigos QR não disponÃvel</translation> + <translation type="unfinished">Suporte para código QR não disponÃvel.</translation> </message> <message> <source>Save QR Code</source> - <translation type="unfinished">Guardar o código QR</translation> + <translation type="unfinished">Guardar código QR</translation> </message> <message> <source>PNG Image</source> @@ -2232,7 +2237,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Client version</source> - <translation type="unfinished">Versão do Cliente</translation> + <translation type="unfinished">Versão do cliente</translation> </message> <message> <source>&Information</source> @@ -2243,16 +2248,24 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <translation type="unfinished">Geral</translation> </message> <message> + <source>Datadir</source> + <translation type="unfinished">Pasta de dados</translation> + </message> + <message> <source>To specify a non-default location of the data directory use the '%1' option.</source> <translation type="unfinished">Para especificar um local não padrão da pasta de dados, use a opção '%1'.</translation> </message> <message> + <source>Blocksdir</source> + <translation type="unfinished">Pasta de blocos</translation> + </message> + <message> <source>To specify a non-default location of the blocks directory use the '%1' option.</source> <translation type="unfinished">Para especificar um local não padrão da pasta dos blocos, use a opção '%1'.</translation> </message> <message> <source>Startup time</source> - <translation type="unfinished">Hora de Arranque</translation> + <translation type="unfinished">Hora de arranque</translation> </message> <message> <source>Network</source> @@ -2264,7 +2277,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Number of connections</source> - <translation type="unfinished">Número de ligações</translation> + <translation type="unfinished">Número de conexões</translation> </message> <message> <source>Block chain</source> @@ -2272,7 +2285,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Memory Pool</source> - <translation type="unfinished">Banco de Memória</translation> + <translation type="unfinished">Pool de memória</translation> </message> <message> <source>Current number of transactions</source> @@ -2280,7 +2293,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Memory usage</source> - <translation type="unfinished">Utilização de memória</translation> + <translation type="unfinished">Utilização da memória</translation> </message> <message> <source>Wallet: </source> @@ -2292,7 +2305,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>&Reset</source> - <translation type="unfinished">&Reiniciar</translation> + <translation type="unfinished">&Repor</translation> </message> <message> <source>Received</source> @@ -2328,7 +2341,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Session ID</source> - <translation type="unfinished">ID de sessão</translation> + <translation type="unfinished">ID da sessão</translation> </message> <message> <source>Version</source> @@ -2336,7 +2349,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Whether we relay transactions to this peer.</source> - <translation type="unfinished">Se retransmitimos transações para este nó.</translation> + <translation type="unfinished">Se retransmitimos transações para este par.</translation> </message> <message> <source>Transaction Relay</source> @@ -2344,19 +2357,19 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Starting Block</source> - <translation type="unfinished">Bloco Inicial</translation> + <translation type="unfinished">Bloco inicial</translation> </message> <message> <source>Synced Headers</source> - <translation type="unfinished">Cabeçalhos Sincronizados</translation> + <translation type="unfinished">Cabeçalhos sincronizados</translation> </message> <message> <source>Synced Blocks</source> - <translation type="unfinished">Blocos Sincronizados</translation> + <translation type="unfinished">Blocos sincronizados</translation> </message> <message> <source>Last Transaction</source> - <translation type="unfinished">Última Transação</translation> + <translation type="unfinished">Última transação</translation> </message> <message> <source>The mapped Autonomous System used for diversifying peer selection.</source> @@ -2364,12 +2377,12 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Mapped AS</source> - <translation type="unfinished">Mapeado como</translation> + <translation type="unfinished">S.A. 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, which displays whether we relay addresses to this peer (Yes/No).</extracomment> - <translation type="unfinished">Endereços são retransmitidos para este nó.</translation> + <translation type="unfinished">Se retransmitimos endereços para este par.</translation> </message> <message> <source>Address Relay</source> @@ -2379,22 +2392,26 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <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> + <translation type="unfinished">O número total de endereços recebidos deste par que foram processados (exclui os endereços que foram eliminados devido à limitação da 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> + <translation type="unfinished">O número total de endereços recebidos deste par que foram descartados (não processados) devido à limitação de 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> + <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> + <translation type="unfinished">Endereços rejeitados devido a limitação de volume</translation> + </message> + <message> + <source>User Agent</source> + <translation type="unfinished">Agente do utilizador</translation> </message> <message> <source>Node window</source> @@ -2406,7 +2423,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </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">Abrir o ficheiro de registo de depuração %1 da pasta de dados atual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation> + <translation type="unfinished">Abrir o ficheiro de registo de depuração %1 da pasta de dados atual. Isto pode demorar alguns segundos para ficheiros de registo grandes.</translation> </message> <message> <source>Decrease font size</source> @@ -2426,7 +2443,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Direction/Type</source> - <translation type="unfinished">Direção/tipo</translation> + <translation type="unfinished">Direção / tipo</translation> </message> <message> <source>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> @@ -2437,12 +2454,16 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <translation type="unfinished">Serviços</translation> </message> <message> + <source>High bandwidth BIP152 compact block relay: %1</source> + <translation type="unfinished">Relé de bloco compacto BIP152 de largura de banda elevada: %1</translation> + </message> + <message> <source>High Bandwidth</source> - <translation type="unfinished">Alta largura de banda</translation> + <translation type="unfinished">Largura de banda elevada</translation> </message> <message> <source>Connection Time</source> - <translation type="unfinished">Tempo de Ligação</translation> + <translation type="unfinished">Tempo de conexão</translation> </message> <message> <source>Elapsed time since a novel block passing initial validity checks was received from this peer.</source> @@ -2455,19 +2476,19 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <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">Tempo decorrido desde que uma nova transação aceite para a nossa mempool foi recebida deste par.</translation> + <translation type="unfinished">Tempo decorrido desde que foi recebida deste par uma nova transação aceite na nossa pool de memória.</translation> </message> <message> <source>Last Send</source> - <translation type="unfinished">Último Envio</translation> + <translation type="unfinished">Último envio</translation> </message> <message> <source>Last Receive</source> - <translation type="unfinished">Último Recebimento</translation> + <translation type="unfinished">Última receção</translation> </message> <message> <source>Ping Time</source> - <translation type="unfinished">Tempo de Latência</translation> + <translation type="unfinished">Tempo de latência</translation> </message> <message> <source>The duration of a currently outstanding ping.</source> @@ -2475,15 +2496,15 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>Ping Wait</source> - <translation type="unfinished">Espera do Ping</translation> + <translation type="unfinished">Espera da latência</translation> </message> <message> <source>Min Ping</source> - <translation type="unfinished">Latência mÃnima</translation> + <translation type="unfinished">Ping mÃnimo</translation> </message> <message> <source>Time Offset</source> - <translation type="unfinished">Fuso Horário</translation> + <translation type="unfinished">Desvio de tempo</translation> </message> <message> <source>Last block time</source> @@ -2499,7 +2520,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>&Network Traffic</source> - <translation type="unfinished">&Tráfego de Rede</translation> + <translation type="unfinished">&Tráfego de rede</translation> </message> <message> <source>Totals</source> @@ -2524,34 +2545,59 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <message> <source>Inbound: initiated by peer</source> <extracomment>Explanatory text for an inbound peer connection.</extracomment> - <translation type="unfinished">Entrando: iniciado por par</translation> + <translation type="unfinished">Entrada: iniciado pelo 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">Relé completo de saÃda: predefinição</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">Relé de bloco de saÃda: não retransmite transações ou endereços</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 de saÃda: adicionado utilizando as opções de configuração RPC %1 ou %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">Sensor (feeler) de saÃda: de curta duração, para testar endereços</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">Obtenção de endereço de saÃda: de curta duração, para solicitar endereços</translation> </message> <message> <source>detecting: peer could be v1 or v2</source> <extracomment>Explanatory text for "detecting" transport type.</extracomment> - <translation type="unfinished">detectando: o par pode ser v1 ou v2</translation> + <translation type="unfinished">a detetar: o par pode ser v1 ou v2</translation> </message> <message> <source>v1: unencrypted, plaintext transport protocol</source> <extracomment>Explanatory text for v1 transport type.</extracomment> - <translation type="unfinished">v1: protocolo de transporte de texto simples não criptografado</translation> + <translation type="unfinished">v1: protocolo de transporte de texto simples e não encriptado</translation> </message> <message> <source>v2: BIP324 encrypted transport protocol</source> <extracomment>Explanatory text for v2 transport type.</extracomment> - <translation type="unfinished">v2: protocolo de transporte criptografado BIP324</translation> + <translation type="unfinished">v2: protocolo de transporte encriptado BIP324</translation> </message> <message> <source>we selected the peer for high bandwidth relay</source> - <translation type="unfinished">selecionámos o par para uma retransmissão de alta banda larga</translation> + <translation type="unfinished">selecionámos o par para retransmissão de largura de banda elevada</translation> </message> <message> <source>the peer selected us for high bandwidth relay</source> - <translation type="unfinished">o par selecionou-nos para uma retransmissão de alta banda larga</translation> + <translation type="unfinished">o par selecionou-nos para uma retransmissão de largura de banda elevada</translation> </message> <message> <source>no high bandwidth relay selected</source> - <translation type="unfinished">nenhum retransmissor de alta banda larga selecionado</translation> + <translation type="unfinished">nenhum retransmissor de largura de banda elevada selecionado</translation> </message> <message> <source>&Copy address</source> @@ -2568,7 +2614,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI </message> <message> <source>1 d&ay</source> - <translation type="unfinished">1 di&a</translation> + <translation type="unfinished">1 &dia</translation> </message> <message> <source>1 &week</source> @@ -2581,7 +2627,7 @@ Se está a receber este erro, deverá pedir ao comerciante para fornecer um URI <message> <source>&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">&Copiar IP/Netmask</translation> + <translation type="unfinished">&Copiar IP / máscara de rede</translation> </message> <message> <source>&Unban</source> @@ -2612,18 +2658,18 @@ 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">Bem vindo à %1 consola RPC. + <translation type="unfinished">Bem-vindo à %1 consola RPC. Utilize as setas para cima e para baixo para navegar no histórico, e %2 para limpar o ecrã. Utilize o %3 e %4 para aumentar ou diminuir o tamanho da letra. Escreva %5 para uma visão geral dos comandos disponÃveis. Para mais informação acerca da utilização desta consola, escreva %6. -%7ATENÇÃO: Foram notadas burlas, dizendo aos utilizadores para escreverem comandos aqui, roubando os conteúdos da sua carteira. Não utilize esta consola sem perceber as ramificações de um comando.%8</translation> +%7ATENÇÃO: foram notadas burlas, dizendo aos utilizadores para escreverem comandos aqui, roubando os conteúdos da sua carteira. Não utilize esta consola sem perceber as ramificações de um comando.%8</translation> </message> <message> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> - <translation type="unfinished">A executar...</translation> + <translation type="unfinished">A executar…</translation> </message> <message> <source>(peer: %1)</source> @@ -2674,7 +2720,7 @@ Para mais informação acerca da utilização desta consola, escreva %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">Uma mensagem opcional para anexar ao pedido de pagamento, que será exibida quando o pedido for aberto. Nota: A mensagem não será enviada com o pagamento através da rede Bitcoin.</translation> + <translation type="unfinished">Uma mensagem opcional a anexar ao pedido de pagamento, que será mostrada quando o pedido for aberto. Nota: a mensagem não será enviada com o pagamento através da rede Bitcoin.</translation> </message> <message> <source>An optional label to associate with the new receiving address.</source> @@ -2682,19 +2728,19 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation type="unfinished">Utilize este formulário para solicitar pagamentos. Todos os campos são <b>opcionais</b>.</translation> + <translation type="unfinished">Utilize este formulário para pedir pagamentos. Todos os campos são <b>opcionais</b>.</translation> </message> <message> <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> - <translation type="unfinished">Uma quantia opcional a solicitar. Deixe em branco ou zero para não solicitar uma quantidade especÃfica.</translation> + <translation type="unfinished">Uma quantia opcional a solicitar. Deixe em branco ou zero para não solicitar uma quantia 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">Um legenda opcional para associar com o novo endereço de recebimento (usado por você para identificar uma fatura). Ela é também anexada ao pedido de pagamento.</translation> + <translation type="unfinished">Uma etiqueta opcional para associar ao novo endereço de receção (usada por si para identificar uma fatura). É também anexada ao pedido de pagamento.</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">Uma mensagem opicional que é anexada ao pedido de pagamento e pode ser mostrada para o remetente.</translation> + <translation type="unfinished">Uma mensagem opcional que é anexada ao pedido de pagamento e que pode ser mostrada ao remetente.</translation> </message> <message> <source>&Create new receiving address</source> @@ -2710,7 +2756,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Requested payments history</source> - <translation type="unfinished">Histórico de pagamentos solicitados</translation> + <translation type="unfinished">Histórico de pagamentos pedidos</translation> </message> <message> <source>Show the selected request (does the same as double clicking an entry)</source> @@ -2749,6 +2795,10 @@ Para mais informação acerca da utilização desta consola, escreva %6. <translation type="unfinished">Copiar &quantia</translation> </message> <message> + <source>Base58 (Legacy)</source> + <translation type="unfinished">Base58 (legado)</translation> + </message> + <message> <source>Not recommended due to higher fees and less protection against typos.</source> <translation type="unfinished">Não recomendado devido a taxas mais altas e menor proteção contra erros de digitação.</translation> </message> @@ -2762,7 +2812,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source> - <translation type="unfinished">Bech32m (BIP-350) é uma atualização para o Bech32,</translation> + <translation type="unfinished">O Bech32m (BIP-350) é uma atualização do Bech32, mas o suporte da carteira ainda é limitado.</translation> </message> <message> <source>Could not unlock wallet.</source> @@ -2789,7 +2839,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Label:</source> - <translation type="unfinished">Legenda:</translation> + <translation type="unfinished">Etiqueta:</translation> </message> <message> <source>Message:</source> @@ -2805,7 +2855,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Copy &Address</source> - <translation type="unfinished">Copi&ar Endereço</translation> + <translation type="unfinished">Copi&ar endereço</translation> </message> <message> <source>&Verify</source> @@ -2813,7 +2863,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Verify this address on e.g. a hardware wallet screen</source> - <translation type="unfinished">Verifique este endreço, por exemplo, no ecrã de uma wallet fÃsica</translation> + <translation type="unfinished">Verifique este endereço, por exemplo, no ecrã de uma carteira fÃsica</translation> </message> <message> <source>&Save Image…</source> @@ -2821,11 +2871,11 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Payment information</source> - <translation type="unfinished">Informação de Pagamento</translation> + <translation type="unfinished">Informação de pagamento</translation> </message> <message> <source>Request payment to %1</source> - <translation type="unfinished">Requisitar Pagamento para %1</translation> + <translation type="unfinished">Pedir pagamento a %1</translation> </message> </context> <context> @@ -2863,15 +2913,15 @@ Para mais informação acerca da utilização desta consola, escreva %6. <name>SendCoinsDialog</name> <message> <source>Send Coins</source> - <translation type="unfinished">Enviar Moedas</translation> + <translation type="unfinished">Enviar moedas</translation> </message> <message> <source>Coin Control Features</source> - <translation type="unfinished">Funcionalidades do Controlo de Moedas:</translation> + <translation type="unfinished">Funcionalidades do controlo de moedas</translation> </message> <message> <source>automatically selected</source> - <translation type="unfinished">selecionadas automáticamente</translation> + <translation type="unfinished">selecionadas automaticamente</translation> </message> <message> <source>Insufficient funds!</source> @@ -2891,7 +2941,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>After Fee:</source> - <translation type="unfinished">Depois da taxa:</translation> + <translation type="unfinished">Após a taxa:</translation> </message> <message> <source>Change:</source> @@ -2915,7 +2965,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Warning: Fee estimation is currently not possible.</source> - <translation type="unfinished">Aviso: atualmente, não é possÃvel a estimativa da taxa.</translation> + <translation type="unfinished">Aviso: neste momento não é possÃvel fazer uma estimativa das taxas.</translation> </message> <message> <source>per kilobyte</source> @@ -2939,7 +2989,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Add &Recipient</source> - <translation type="unfinished">Adicionar &Destinatário</translation> + <translation type="unfinished">Adicionar &destinatário</translation> </message> <message> <source>Clear all fields of the form.</source> @@ -2947,7 +2997,7 @@ Para mais informação acerca da utilização desta consola, escreva %6. </message> <message> <source>Inputs…</source> - <translation type="unfinished">Entradas...</translation> + <translation type="unfinished">Entradas…</translation> </message> <message> <source>Choose…</source> @@ -2963,35 +3013,35 @@ Para mais informação acerca da utilização desta consola, escreva %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">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> +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> + <translation type="unfinished">Quando há menos volume de transações do que espaço nos blocos, os mineradores, bem como os pares de retransmissão, podem impor uma taxa mÃnima. Pagar apenas esta taxa mÃnima não faz mal, mas tenha em atenção que isto pode resultar numa transação nunca confirmada, uma vez que há mais procura de transações de bitcoin do que a rede pode processar.</translation> </message> <message> <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation type="unfinished">Uma taxa muito baixa pode resultar numa transação nunca confirmada (leia a dica)</translation> + <translation type="unfinished">Uma taxa muito baixa pode resultar numa transação nunca confirmada (leia a dica no menu de contexto)</translation> </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks…)</source> - <translation type="unfinished">(A taxa inteligente ainda não foi inicializada. Isto demora normalmente alguns blocos...)</translation> + <translation type="unfinished">(A taxa inteligente ainda não foi inicializada. Isto demora normalmente alguns blocos…)</translation> </message> <message> <source>Confirmation time target:</source> - <translation type="unfinished">Tempo de confirmação:</translation> + <translation type="unfinished">Objetivo de tempo de confirmação:</translation> </message> <message> <source>Enable Replace-By-Fee</source> - <translation type="unfinished">Ativar substituir-por-taxa</translation> + <translation type="unfinished">Ativar "substituir por taxa"</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">Com substituir-por-taxa (BIP-125) pode aumentar a taxa da transação após ela ser enviada. Sem isto, pode ser recomendável uma taxa maior para compensar o risco maior de atraso na transação.</translation> + <translation type="unfinished">Com "substituir por taxa" (Replace-By-Fee) (BIP-125) pode aumentar a taxa da transação após ela ser enviada. Sem isto, pode ser recomendável uma taxa maior para compensar o risco maior de atraso na transação.</translation> </message> <message> <source>Clear &All</source> - <translation type="unfinished">Limpar &Tudo</translation> + <translation type="unfinished">Limpar &tudo</translation> </message> <message> <source>Balance:</source> @@ -2999,7 +3049,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Confirm the send action</source> - <translation type="unfinished">Confirme ação de envio</translation> + <translation type="unfinished">Confirme o envio</translation> </message> <message> <source>S&end</source> @@ -3011,7 +3061,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Copy amount</source> - <translation type="unfinished">Copiar valor</translation> + <translation type="unfinished">Copiar quantia</translation> </message> <message> <source>Copy fee</source> @@ -3019,7 +3069,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Copy after fee</source> - <translation type="unfinished">Copiar depois da taxa</translation> + <translation type="unfinished">Copiar após a taxa</translation> </message> <message> <source>Copy bytes</source> @@ -3036,11 +3086,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <message> <source>Sign on device</source> <extracomment>"device" usually means a hardware wallet.</extracomment> - <translation type="unfinished">entrar no dispositivo</translation> + <translation type="unfinished">Assinar no dispositivo</translation> </message> <message> <source>Connect your hardware wallet first.</source> - <translation type="unfinished">Por favor conecte a sua wallet fÃsica primeiro.</translation> + <translation type="unfinished">Conecte primeiro a sua carteira de hardware.</translation> </message> <message> <source>Set external signer script path in Options -> Wallet</source> @@ -3049,15 +3099,15 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Cr&eate Unsigned</source> - <translation type="unfinished">Criar não assinado</translation> + <translation type="unfinished">Criar &não assinado</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">Cria uma transação de Bitcoin parcialmente assinada (PSBT)(sigla em inglês) para ser usada por exemplo com uma carteira %1 offline ou uma carteira de hardware compatÃvel com PSBT.</translation> + <translation type="unfinished">Cria uma transação de Bitcoin parcialmente assinada (PSBT - sigla em inglês) para ser usada por exemplo com uma carteira %1 offline ou uma carteira de hardware compatÃvel com PSBT.</translation> </message> <message> <source>%1 to '%2'</source> - <translation type="unfinished">%1 a '%2'</translation> + <translation type="unfinished">%1 para '%2'</translation> </message> <message> <source>%1 to %2</source> @@ -3065,7 +3115,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>To review recipient list click "Show Details…"</source> - <translation type="unfinished">Para rever a lista de destinatários clique "Mostrar detalhes..."</translation> + <translation type="unfinished">Para rever a lista de destinatários clique em "Mostrar detalhes…"</translation> </message> <message> <source>Sign failed</source> @@ -3074,30 +3124,30 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <message> <source>External signer not found</source> <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Signatário externo não encontrado</translation> + <translation type="unfinished">Assinante externo não encontrado</translation> </message> <message> <source>External signer failure</source> <extracomment>"External signer" means using devices such as hardware wallets.</extracomment> - <translation type="unfinished">Falha do signatário externo</translation> + <translation type="unfinished">Falha do assinante externo</translation> </message> <message> <source>Save Transaction Data</source> - <translation type="unfinished">Salvar informação de transação</translation> + <translation type="unfinished">Guardar informação da transação</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">Transação parcialmente assinada (Binário)</translation> + <translation type="unfinished">Transação parcialmente assinada (binário)</translation> </message> <message> <source>PSBT saved</source> <extracomment>Popup message when a PSBT has been saved to a file</extracomment> - <translation type="unfinished">PSBT salva</translation> + <translation type="unfinished">PSBT guardada</translation> </message> <message> <source>External balance:</source> - <translation type="unfinished">Balanço externo:</translation> + <translation type="unfinished">Saldo externo:</translation> </message> <message> <source>or</source> @@ -3105,16 +3155,16 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation type="unfinished">Pode aumentar a taxa depois (sinaliza substituir-por-taxa, BIP-125).</translation> + <translation type="unfinished">Pode aumentar a taxa depois (sinaliza "substituir por taxa", 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, 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> + <translation type="unfinished">Por favor, reveja a sua proposta de transação. Isto produzirá uma transação Bitcoin parcialmente assinada (PSBT) que pode guardar ou copiar e depois assinar com, por exemplo, uma carteira %1 offline, ou uma carteira de hardware compatÃvel com PSBT.</translation> </message> <message> <source>%1 from wallet '%2'</source> - <translation type="unfinished">%1 da pasta "%2</translation> + <translation type="unfinished">%1 da carteira "%2"</translation> </message> <message> <source>Do you want to create this transaction?</source> @@ -3124,7 +3174,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <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> + <translation type="unfinished">Por favor, reveja a sua transação. Pode criar e enviar esta transação ou criar uma transação Bitcoin parcialmente assinada (PSBT), que pode guardar ou copiar e depois assinar com, por exemplo, uma carteira %1 offline, ou uma carteira de hardware compatÃvel com PSBT.</translation> </message> <message> <source>Please, review your transaction.</source> @@ -3137,25 +3187,25 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation type="unfinished">Não sinalizar substituir-por-taxa, BIP-125.</translation> + <translation type="unfinished">Não indica "substituir por taxa", BIP-125.</translation> </message> <message> <source>Total Amount</source> - <translation type="unfinished">Valor Total</translation> + <translation type="unfinished">Quantia total</translation> </message> <message> <source>Unsigned Transaction</source> <comment>PSBT copied</comment> <extracomment>Caption of "PSBT has been copied" messagebox</extracomment> - <translation type="unfinished">Transação Não Assinada</translation> + <translation type="unfinished">Transação não assinada</translation> </message> <message> <source>The PSBT has been copied to the clipboard. You can also save it.</source> - <translation type="unfinished">O PSBT foi salvo na área de transferência. Você pode também salva-lo.</translation> + <translation type="unfinished">O PSBT foi copiado para a área de transferência. Também o pode guardar.</translation> </message> <message> <source>PSBT saved to disk</source> - <translation type="unfinished">PSBT salvo no disco.</translation> + <translation type="unfinished">PSBT guardada no disco</translation> </message> <message> <source>Confirm send coins</source> @@ -3163,19 +3213,19 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Watch-only balance:</source> - <translation type="unfinished">Saldo apenas para visualização:</translation> + <translation type="unfinished">Saldo de observação:</translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> - <translation type="unfinished">O endereço do destinatário é inválido. Por favor, reverifique.</translation> + <translation type="unfinished">O endereço do destinatário não é válido. Por favor, verifique novamente.</translation> </message> <message> <source>The amount to pay must be larger than 0.</source> - <translation type="unfinished">O valor a pagar dever maior que 0.</translation> + <translation type="unfinished">A quantia a pagar dever maior que 0.</translation> </message> <message> <source>The amount exceeds your balance.</source> - <translation type="unfinished">O valor excede o seu saldo.</translation> + <translation type="unfinished">A quantia excede o seu saldo.</translation> </message> <message> <source>The total exceeds your balance when the %1 transaction fee is included.</source> @@ -3191,13 +3241,13 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <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> + <translation type="unfinished">Uma taxa superior a %1 é considerada uma taxa absurdamente elevada.</translation> </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> - <numerusform>Confirmação estimada para iniciar em %n bloco.</numerusform> - <numerusform>Confirmação estimada para iniciar em %n blocos.</numerusform> + <numerusform>Estima-se que a confirmação comece dentro de %n bloco.</numerusform> + <numerusform>Estima-se que a confirmação comece dentro de %n blocos.</numerusform> </translation> </message> <message> @@ -3214,7 +3264,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </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">O endereço que selecionou para alterar não faz parte desta carteira. Qualquer ou todos os fundos na sua carteira podem ser enviados para este endereço. Tem certeza?</translation> + <translation type="unfinished">O endereço que selecionou para o troco não faz parte desta carteira. Todos ou quaisquer fundos na sua carteira podem ser enviados para este endereço. Tem a certeza?</translation> </message> <message> <source>(no label)</source> @@ -3225,11 +3275,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation type="unfinished">Qu&antia:</translation> + <translation type="unfinished">Qua&ntia:</translation> </message> <message> <source>Pay &To:</source> - <translation type="unfinished">&Pagar A:</translation> + <translation type="unfinished">&Pagar a:</translation> </message> <message> <source>&Label:</source> @@ -3241,11 +3291,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>The Bitcoin address to send the payment to</source> - <translation type="unfinished">O endereço Bitcoin para enviar o pagamento</translation> + <translation type="unfinished">O endereço Bitcoin para onde enviar o pagamento</translation> </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">Cole endereço da área de transferência</translation> + <translation type="unfinished">Colar endereço da área de transferência</translation> </message> <message> <source>Remove this entry</source> @@ -3253,15 +3303,15 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>The amount to send in the selected unit</source> - <translation type="unfinished">A quantidade para enviar na unidade selecionada</translation> + <translation type="unfinished">A quantia a enviar na unidade selecionada</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">A taxa será deduzida ao valor que está a ser enviado. O destinatário irá receber menos bitcoins do que as que inseridas no campo do valor. Se estiverem selecionados múltiplos destinatários, a taxa será repartida equitativamente.</translation> + <translation type="unfinished">A taxa será deduzida à quantia que está a ser enviada. O destinatário irá receber menos bitcoins do que as que inseridas no campo da quantia. Se estiverem selecionados múltiplos destinatários, a taxa será repartida equitativamente.</translation> </message> <message> <source>S&ubtract fee from amount</source> - <translation type="unfinished">S&ubtrair a taxa ao montante</translation> + <translation type="unfinished">S&ubtrair a taxa à quantia</translation> </message> <message> <source>Use available balance</source> @@ -3277,7 +3327,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </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">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> + <translation type="unfinished">Uma mensagem que foi anexada ao bitcoin: URI 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> </context> <context> @@ -3295,19 +3345,19 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation type="unfinished">Assinaturas - Assinar / Verificar uma Mensagem</translation> + <translation type="unfinished">Assinaturas - assinar / verificar uma mensagem</translation> </message> <message> <source>&Sign Message</source> - <translation type="unfinished">&Assinar Mensagem</translation> + <translation type="unfinished">&Assinar mensagem</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">Pode assinar mensagens com os seus endereços para provar que são seus. Tenha atenção ao assinar mensagens ambÃguas, pois ataques de phishing podem tentar enganá-lo de modo a assinar a sua identidade para os atacantes. Apenas assine declarações detalhadas com as quais concorde.</translation> + <translation type="unfinished">Pode assinar mensagens/acordos com os seus endereços para provar que pode receber bitcoins enviados para eles. Tenha cuidado para não assinar nada vago ou aleatório, pois os ataques de phishing podem tentar induzi-lo a assinar a sua identidade. Assine apenas declarações totalmente detalhadas com as quais concorda.</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> - <translation type="unfinished">O endereço Bitcoin para designar a mensagem</translation> + <translation type="unfinished">O endereço Bitcoin com o qual assinar a mensagem</translation> </message> <message> <source>Choose previously used address</source> @@ -3315,7 +3365,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Paste address from clipboard</source> - <translation type="unfinished">Cole endereço da área de transferência</translation> + <translation type="unfinished">Colar endereço da área de transferência</translation> </message> <message> <source>Enter the message you want to sign here</source> @@ -3331,11 +3381,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation type="unfinished">Assine uma mensagem para provar que é dono deste endereço Bitcoin</translation> + <translation type="unfinished">Assine a mensagem para provar que é o proprietário deste endereço Bitcoin</translation> </message> <message> <source>Sign &Message</source> - <translation type="unfinished">Assinar &Mensagem</translation> + <translation type="unfinished">Assinar &mensagem</translation> </message> <message> <source>Reset all sign message fields</source> @@ -3343,19 +3393,19 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Clear &All</source> - <translation type="unfinished">Limpar &Tudo</translation> + <translation type="unfinished">Limpar &tudo</translation> </message> <message> <source>&Verify Message</source> - <translation type="unfinished">&Verificar Mensagem</translation> + <translation type="unfinished">&Verificar mensagem</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">Introduza o endereço de assinatura, mensagem (assegure-se que copia quebras de linha, espaços, tabulações, etc. exatamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem.</translation> + <translation type="unfinished">Introduza o endereço do destinatário, a mensagem (certifique-se que copia com exatidão as quebras de linha, os espaços, tabulações, etc.) e a assinatura abaixo para verificar a mensagem. Tenha cuidado para não ler mais na assinatura do que o que está na própria mensagem assinada, para evitar ser enganado por um ataque de intermediário (man-in-the-middle). Note que isto apenas prova que a parte que assina recebe com este endereço, não podendo provar o remetente de nenhuma transação!</translation> </message> <message> <source>The Bitcoin address the message was signed with</source> - <translation type="unfinished">O endereço Bitcoin com que a mensagem foi designada</translation> + <translation type="unfinished">O endereço Bitcoin com o qual a mensagem foi assinada</translation> </message> <message> <source>The signed message to verify</source> @@ -3371,7 +3421,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Verify &Message</source> - <translation type="unfinished">Verificar &Mensagem</translation> + <translation type="unfinished">Verificar &mensagem</translation> </message> <message> <source>Reset all verify message fields</source> @@ -3379,7 +3429,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Click "Sign Message" to generate signature</source> - <translation type="unfinished">Clique "Assinar Mensagem" para gerar a assinatura</translation> + <translation type="unfinished">Clique em "Assinar mensagem" para gerar a assinatura</translation> </message> <message> <source>The entered address is invalid.</source> @@ -3391,7 +3441,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>The entered address does not refer to a key.</source> - <translation type="unfinished">O endereço introduzido não refere-se a nenhuma chave.</translation> + <translation type="unfinished">O endereço introduzido não se refere a uma chave.</translation> </message> <message> <source>Wallet unlock was cancelled.</source> @@ -3399,7 +3449,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>No error</source> - <translation type="unfinished">Sem erro</translation> + <translation type="unfinished">Nenhum erro</translation> </message> <message> <source>Private key for the entered address is not available.</source> @@ -3407,7 +3457,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Message signing failed.</source> - <translation type="unfinished">Assinatura da mensagem falhou.</translation> + <translation type="unfinished">A assinatura da mensagem falhou.</translation> </message> <message> <source>Message signed.</source> @@ -3423,11 +3473,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>The signature did not match the message digest.</source> - <translation type="unfinished">A assinatura não corresponde com o conteúdo da mensagem.</translation> + <translation type="unfinished">A assinatura não corresponde ao resumo da mensagem.</translation> </message> <message> <source>Message verification failed.</source> - <translation type="unfinished">Verificação da mensagem falhou.</translation> + <translation type="unfinished">A verificação da mensagem falhou.</translation> </message> <message> <source>Message verified.</source> @@ -3438,11 +3488,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <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> + <translation type="unfinished">(pressione Q para desligar e continuar mais tarde)</translation> </message> <message> <source>press q to shutdown</source> - <translation type="unfinished">Carregue q para desligar</translation> + <translation type="unfinished">pressione Q para desligar</translation> </message> </context> <context> @@ -3450,17 +3500,17 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <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> + <translation type="unfinished">em conflito com uma transação com %1 confirmações</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/não confirmada, no memory pool</translation> + <translation type="unfinished">0/não confirmado, na pool de memória</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/não confirmada, ausente no memory pool</translation> + <translation type="unfinished">0/não confirmado, não está na pool de memória</translation> </message> <message> <source>abandoned</source> @@ -3470,7 +3520,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <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> + <translation type="unfinished">%1/não confirmado</translation> </message> <message> <source>%1 confirmations</source> @@ -3491,7 +3541,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Generated</source> - <translation type="unfinished">Gerado</translation> + <translation type="unfinished">Gerada</translation> </message> <message> <source>From</source> @@ -3507,11 +3557,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>own address</source> - <translation type="unfinished">endereço próprio</translation> + <translation type="unfinished">próprio endereço</translation> </message> <message> <source>watch-only</source> - <translation type="unfinished">apenas vigiar</translation> + <translation type="unfinished">apenas observação</translation> </message> <message> <source>label</source> @@ -3524,8 +3574,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>pronta em mais %n bloco</numerusform> - <numerusform>prontas em mais %n blocos</numerusform> + <numerusform>maturo em mais %n bloco</numerusform> + <numerusform>maturo em mais %n blocos</numerusform> </translation> </message> <message> @@ -3550,7 +3600,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Net amount</source> - <translation type="unfinished">Valor lÃquido</translation> + <translation type="unfinished">Quantia lÃquida</translation> </message> <message> <source>Message</source> @@ -3562,11 +3612,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Transaction ID</source> - <translation type="unfinished">Id. da Transação</translation> + <translation type="unfinished">ID da transação</translation> </message> <message> <source>Transaction total size</source> - <translation type="unfinished">Tamanho total da transição</translation> + <translation type="unfinished">Tamanho total da transação</translation> </message> <message> <source>Transaction virtual size</source> @@ -3574,12 +3624,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Output index</source> - <translation type="unfinished">Ãndex de saÃda</translation> + <translation type="unfinished">Ãndice de saÃda</translation> </message> <message> <source>%1 (Certificate was not verified)</source> - <translation type="unfinished"> -%1 (O certificado não foi verificado)</translation> + <translation type="unfinished">%1 (O certificado não foi verificado)</translation> </message> <message> <source>Merchant</source> @@ -3587,7 +3636,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </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">As moedas geradas precisam amadurecer %1 blocos antes que possam ser gastas. Quando gerou este bloco, ele foi transmitido para a rede para ser adicionado à cadeia de blocos. Se este não conseguir entrar na cadeia, seu estado mudará para "não aceite" e não poderá ser gasto. Isto pode acontecer ocasionalmente se outro nó gerar um bloco dentro de alguns segundos do seu.</translation> + <translation type="unfinished">As moedas geradas têm de amadurecer %1 blocos antes que possam ser gastas. Quando gerou este bloco, ele foi transmitido para a rede para ser adicionado à cadeia de blocos. Se este não conseguir entrar na cadeia, o seu estado mudará para "não aceite" e não poderá ser gasto. Isto pode acontecer ocasionalmente se outro nó gerar um bloco dentro de alguns segundos do seu.</translation> </message> <message> <source>Debug information</source> @@ -3653,11 +3702,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Confirmed (%1 confirmations)</source> - <translation type="unfinished">Confirmada (%1 confirmações)</translation> + <translation type="unfinished">Confirmado (%1 confirmações)</translation> </message> <message> <source>Conflicted</source> - <translation type="unfinished">IncompatÃvel</translation> + <translation type="unfinished">Em conflito</translation> </message> <message> <source>Immature (%1 confirmations, will be available after %2)</source> @@ -3685,7 +3734,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>watch-only</source> - <translation type="unfinished">apenas vigiar</translation> + <translation type="unfinished">apenas observação</translation> </message> <message> <source>(n/a)</source> @@ -3709,15 +3758,15 @@ 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">Se um endereço de apenas vigiar está ou não envolvido nesta transação.</translation> + <translation type="unfinished">Se um endereço de observação está ou não envolvido nesta transação.</translation> </message> <message> <source>User-defined intent/purpose of the transaction.</source> - <translation type="unfinished">Intenção do utilizador/motivo da transação</translation> + <translation type="unfinished">Intenção do utilizador / motivo da transação.</translation> </message> <message> <source>Amount removed from or added to balance.</source> - <translation type="unfinished">Montante retirado ou adicionado ao saldo</translation> + <translation type="unfinished">Quantia retirada ou adicionada ao saldo.</translation> </message> </context> <context> @@ -3764,11 +3813,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Enter address, transaction id, or label to search</source> - <translation type="unfinished">Escreva endereço, identificação de transação ou etiqueta para procurar</translation> + <translation type="unfinished">Introduzir endereço, identificador da transação ou etiqueta para procurar</translation> </message> <message> <source>Min amount</source> - <translation type="unfinished">Valor mÃn.</translation> + <translation type="unfinished">Quantia mÃn.</translation> </message> <message> <source>Range…</source> @@ -3788,15 +3837,15 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Copy transaction &ID</source> - <translation type="unfinished">Copiar Id. da transação</translation> + <translation type="unfinished">Copiar ID da transação</translation> </message> <message> <source>Copy &raw transaction</source> - <translation type="unfinished">Copiar &transação bruta</translation> + <translation type="unfinished">Copiar transação em b&ruto</translation> </message> <message> <source>Copy full transaction &details</source> - <translation type="unfinished">Copie toda a transação &details</translation> + <translation type="unfinished">Copiar a transação completa e os &detalhes</translation> </message> <message> <source>&Show transaction details</source> @@ -3821,7 +3870,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Export Transaction History</source> - <translation type="unfinished">Exportar Histórico de Transações</translation> + <translation type="unfinished">Exportar histórico de transações</translation> </message> <message> <source>Comma separated file</source> @@ -3830,11 +3879,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Confirmed</source> - <translation type="unfinished">Confirmada</translation> + <translation type="unfinished">Confirmado</translation> </message> <message> <source>Watch-only</source> - <translation type="unfinished">Apenas vigiar</translation> + <translation type="unfinished">Apenas observação</translation> </message> <message> <source>Date</source> @@ -3853,12 +3902,8 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <translation type="unfinished">Endereço</translation> </message> <message> - <source>ID</source> - <translation type="unfinished">Id.</translation> - </message> - <message> <source>Exporting Failed</source> - <translation type="unfinished">Exportação Falhou</translation> + <translation type="unfinished">Falha na exportação</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> @@ -3866,7 +3911,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Exporting Successful</source> - <translation type="unfinished">Exportação Bem Sucedida</translation> + <translation type="unfinished">Exportação bem sucedida</translation> </message> <message> <source>The transaction history was successfully saved to %1.</source> @@ -3874,7 +3919,7 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para </message> <message> <source>Range:</source> - <translation type="unfinished">PerÃodo:</translation> + <translation type="unfinished">Intervalo:</translation> </message> <message> <source>to</source> @@ -3887,13 +3932,13 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kvB" para <source>No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR -</source> - <translation type="unfinished">Nenhuma carteira foi carregada -Ir para o arquivo > Abrir carteira para carregar a carteira + <translation type="unfinished">Nenhuma carteira foi carregada. +Vá ao menu Ficheiro > Abrir carteira para carregar uma carteira - OU -</translation> </message> <message> <source>Create a new wallet</source> - <translation type="unfinished">Criar novo carteira</translation> + <translation type="unfinished">Criar nova carteira</translation> </message> <message> <source>Error</source> @@ -3901,7 +3946,7 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>Unable to decode PSBT from clipboard (invalid base64)</source> - <translation type="unfinished">Incapaz de decifrar a PSBT da área de transferência (base64 inválida)</translation> + <translation type="unfinished">Não foi possÃvel descodificar a transação de Bitcoin parcialmente assinada (PSTB) da área de transferência (base64 inválida)</translation> </message> <message> <source>Load Transaction Data</source> @@ -3913,18 +3958,18 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>PSBT file must be smaller than 100 MiB</source> - <translation type="unfinished">Arquivo PSBT deve ser menor que 100 MiB</translation> + <translation type="unfinished">O ficheiro PSBT deve ser inferior a 100 MiB</translation> </message> <message> <source>Unable to decode PSBT</source> - <translation type="unfinished">Incapaz de decifrar a PSBT</translation> + <translation type="unfinished">Não foi possÃvel descodificar a transação de Bitcoin parcialmente assinada (PSTB)</translation> </message> </context> <context> <name>WalletModel</name> <message> <source>Send Coins</source> - <translation type="unfinished">Enviar Moedas</translation> + <translation type="unfinished">Enviar moedas</translation> </message> <message> <source>Fee bump error</source> @@ -3932,7 +3977,7 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>Increasing transaction fee failed</source> - <translation type="unfinished">Aumento da taxa de transação falhou</translation> + <translation type="unfinished">O aumento da taxa de transação falhou</translation> </message> <message> <source>Do you want to increase the fee?</source> @@ -3952,8 +3997,12 @@ Ir para o arquivo > Abrir carteira para carregar a carteira <translation type="unfinished">Nova taxa:</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">Aviso: pode pagar a taxa adicional reduzindo as saÃdas ou aumentando as entradas, quando necessário. Poderá ser acrescentada uma nova moeda, caso ainda não exista nenhuma. Estas alterações podem potencialmente causar fugas de privacidade.</translation> + </message> + <message> <source>Confirm fee bump</source> - <translation type="unfinished">Confirme aumento de taxa</translation> + <translation type="unfinished">Confirmar aumento da taxa</translation> </message> <message> <source>Can't draft transaction.</source> @@ -3974,11 +4023,11 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>Could not commit transaction</source> - <translation type="unfinished">Não foi possÃvel cometer a transação</translation> + <translation type="unfinished">Não foi possÃvel confirmar a transação</translation> </message> <message> <source>Can't display address</source> - <translation type="unfinished">Não é possÃvel exibir o endereço</translation> + <translation type="unfinished">Não é possÃvel visualizar o endereço</translation> </message> <message> <source>default wallet</source> @@ -3989,15 +4038,15 @@ Ir para o arquivo > Abrir carteira para carregar a carteira <name>WalletView</name> <message> <source>&Export</source> - <translation type="unfinished">e exportar</translation> + <translation type="unfinished">&Exportar</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation type="unfinished">Exportar os dados no separador atual para um ficheiro</translation> + <translation type="unfinished">Exportar os dados na aba atual para um ficheiro</translation> </message> <message> <source>Backup Wallet</source> - <translation type="unfinished">Cópia de Segurança da Carteira</translation> + <translation type="unfinished">Cópia de segurança da carteira</translation> </message> <message> <source>Wallet Data</source> @@ -4006,7 +4055,7 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>Backup Failed</source> - <translation type="unfinished">Cópia de Segurança Falhou</translation> + <translation type="unfinished">Falha na cópia de segurança</translation> </message> <message> <source>There was an error trying to save the wallet data to %1.</source> @@ -4014,7 +4063,7 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>Backup Successful</source> - <translation type="unfinished">Cópia de Segurança Bem Sucedida</translation> + <translation type="unfinished">Cópia de segurança efetuada com êxito</translation> </message> <message> <source>The wallet data was successfully saved to %1.</source> @@ -4033,60 +4082,87 @@ Ir para o arquivo > Abrir carteira para carregar a carteira </message> <message> <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> - <translation type="unfinished">%s corrompido. Tente usar a ferramenta de carteira bitcoin-wallet para salvar ou restaurar um backup.</translation> + <translation type="unfinished">%s corrompido. Tente usar a ferramenta de carteira bitcoin-wallet para guardar ou restaurar uma cópia de segurança.</translation> </message> <message> <source>%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 will be left on disk in case it is helpful in diagnosing the issue that caused this error.</source> - <translation type="unfinished">%s falhou ao validar o estado da cópia -assumeutxo. Isso indica um problema de hardware, um bug no software ou uma modificação incorreta do software que permitiu o carregamento de uma cópia inválida. Como resultado disso, o nó será desligado e parará de usar qualquer estado criado na cópia, redefinindo a altura da corrente de %d para %d. Na próxima reinicialização, o nó retomará a sincronização de%d sem usar nenhum dado da cópia. Por favor, reporte este incidente para %s, incluindo como você obteve a cópia. A cópia inválida do estado de cadeia será deixada no disco caso sirva para diagnosticar o problema que causou esse erro.</translation> + <translation type="unfinished">%s falhou ao validar o estado do instantâneo -assumeutxo. Isso indica um problema de hardware ou um erro no software ou uma modificação de software incorreta que permitiu que um instantâneo inválido fosse carregado. Como resultado disso, o nó será desligado e deixará de usar qualquer estado que tenha sido construÃdo no instantâneo, redefinindo a altura da cadeia de %d para %d. Na próxima reinicialização, o nó retomará a sincronização a partir de %d sem utilizar quaisquer dados de instantâneos. Por favor, comunique este incidente a %s, incluindo a forma como obteve o instantâneo. O estado em cadeia do instantâneo inválido será deixado no disco, caso seja útil para diagnosticar o problema que causou este erro.</translation> </message> <message> <source>%s request to listen on port %u. This port is considered "bad" 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">1%s solicitação para escutar na porta 2%u. Esta porta é considerada "ruim" e, portanto, é improvável que qualquer ponto se conecte-se a ela. Consulte doc/p2p-bad-ports.md para obter detalhes e uma lista completa.</translation> + <translation type="unfinished">%s solicita a escuta na porta %u. Esta porta é considerada "má" e, por isso, é improvável que qualquer par se conecte a ela. Veja doc/p2p-bad-ports.md para detalhes e uma lista completa.</translation> </message> <message> <source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> - <translation type="unfinished">Não é possÃvel fazer o downgrade da carteira da versão %i para %i. Versão da carteira inalterada.</translation> + <translation type="unfinished">Não é possÃvel fazer o downgrade da carteira da versão %i para %i. A versão da carteira não foi alterada.</translation> </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation type="unfinished">Não foi possÃvel obter o bloqueio de escrita no da pasta de dados %s. %s provavelmente já está a ser executado.</translation> + <translation type="unfinished">Não foi possÃvel obter o bloqueio de escrita da pasta de dados %s. %s provavelmente já está em execução.</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">Não é possÃvel atualizar uma carteira não dividida em HD da versão %i para a versão %i sem atualizar para suportar o conjunto de chaves pré-dividido. Por favor, use a versão %i ou nenhuma versão especificada.</translation> </message> <message> <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">O espaço em disco para 1%s pode não acomodar os arquivos de bloco. Aproximadamente 2%u GB de dados serão armazenados neste diretório.</translation> + <translation type="unfinished">O espaço em disco para %s pode não acomodar os ficheiros de bloco. Serão armazenados neste diretório aproximadamente %u GB de dados.</translation> </message> <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation type="unfinished">DistribuÃdo sob licença de software MIT, veja o ficheiro %s ou %s</translation> + <translation type="unfinished">DistribuÃdo sob a licença de software MIT, ver o ficheiro que o acompanha %s ou %s</translation> </message> <message> <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">Erro ao carregar a carteira. A carteira requer que os blocos sejam baixados e o software atualmente não suporta o carregamento de carteiras enquanto os blocos estão sendo baixados fora de ordem ao usar instantâneos assumeutxo. A carteira deve ser carregada com êxito após a sincronização do nó atingir o patamar 1%s</translation> + <translation type="unfinished">Erro ao carregar a carteira. A carteira requer que os blocos sejam descarregados, e o software não suporta atualmente o carregamento de carteiras enquanto os blocos estão a ser descarregados fora de ordem quando se utilizam instantâneos "assumeutxo". A carteira deve poder ser carregada com sucesso depois que a sincronização do nó atingir a altura %s</translation> </message> <message> <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> + <translation type="unfinished">Erro ao ler %s! Os dados da transação podem estar em falta ou incorretos. A verificar novamente a carteira.</translation> + </message> + <message> + <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <translation type="unfinished">Erro: o registo do formato do ficheiro de dump está incorreto. Obteve-se "%s", mas era esperado "format".</translation> + </message> + <message> + <source>Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> + <translation type="unfinished">Erro: o registo do identificador do ficheiro de dump está incorreto. Obteve-se "%s", mas era esperado "%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">Erro: Esta versão do bitcoin-wallet apenas suporta arquivos de despejo na versão 1. (Versão atual: %s)</translation> + <translation type="unfinished">Erro: esta versão do bitcoin-wallet apenas suporta ficheiros dump na versão 1. (Versão atual: %s)</translation> + </message> + <message> + <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> + <translation type="unfinished">Erro: as carteiras legadas apenas suportam os tipos de endereço "legado", "p2sh-segwit" e "bech32</translation> + </message> + <message> + <source>Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.</source> + <translation type="unfinished">Erro: não é possÃvel produzir descritores para esta carteira antiga. Certifique-se de que fornece a frase de segurança da carteira se esta estiver encriptada.</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">Arquivo%sjá existe. Se você tem certeza de que é isso que quer, tire-o do caminho primeiro.</translation> + <translation type="unfinished">O ficheiro%s já existe. Se tem a certeza que é isso que quer, mova-o primeiro para fora do caminho.</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> + <translation type="unfinished">O ficheiro peers.dat (%s) está corrompido ou é inválido. Se acredita qua se trata de um "bug", por favor reporte para %s. Como solução, pode mover, alterar o nome ou eliminar (%s) para ser criado um novo 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 de ligação onion é fornecido. Usando %s para o serviço Tor onion criado automaticamente.</translation> + <translation type="unfinished">É fornecido mais do que um endereço onion bind. A utilizar %s para o serviço Tor onion criado automaticamente.</translation> + </message> + <message> + <source>No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">Não foi fornecido nenhum ficheiro de dump. Para utilizar createfromdump tem de ser fornecido -dumpfile=<filename>.</translation> + </message> + <message> + <source>No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> + <translation type="unfinished">Não foi fornecido nenhum ficheiro de dump. Para utilizar o dump, tem de ser fornecido -dumpfile=<filename>.</translation> </message> <message> <source>No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <translation type="unfinished">Nenhum formato de arquivo de carteira fornecido. Para usar createfromdump, -format = <format> -deve ser fornecido.</translation> + <translation type="unfinished">Não foi fornecido nenhum formato de ficheiro de carteira. Para usar createfromdump, é necessário fornecer -format=<format>.</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> @@ -4098,47 +4174,47 @@ deve ser fornecido.</translation> </message> <message> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> - <translation type="unfinished">Poda configurada abaixo do mÃnimo de %d MiB. Por favor, utilize um valor mais elevado.</translation> + <translation type="unfinished">O modo de redução (prune) está configurado abaixo do mÃnimo de %d MiB. Utilize um valor mais elevado.</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> + <translation type="unfinished">O modo de redução (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">Poda: a última sincronização da carteira vai além dos dados podados. Precisa de -reindex (descarregar novamente a cadeia de blocos completa em caso de nó podado)</translation> + <translation type="unfinished">Redução (prune): a última sincronização da carteira vai além dos dados reduzidos. Precisa de -reindex (descarregar novamente a cadeia de blocos completa no caso de nó com redução)</translation> </message> <message> <source>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.</source> - <translation type="unfinished">Falha ao renomear '%s' -> '%s'. Você deve resolver este problema manualmente movendo ou removendo o diretório de cópia inválido %s, caso contrário o mesmo erro ocorrerá novamente na próxima inicialização.</translation> + <translation type="unfinished">A renomeação de '%s' -> '%s' falhou. Deve resolver este problema movendo ou eliminando manualmente o diretório de instantâneos inválido %s, caso contrário, voltará a encontrar o mesmo erro no arranque seguinte.</translation> </message> <message> <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> - <translation type="unfinished">SQLiteDatabase: Versão %d do esquema de carteira sqlite desconhecido. Apenas a versão %d é suportada</translation> + <translation type="unfinished">SQLiteDatabase: versão %d do esquema de carteira sqlite desconhecido. Apenas é suportada a versão %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">A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorreta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão corretos.</translation> + <translation type="unfinished">A base de dados de blocos contém um bloco que parece ser do futuro. Isto pode dever-se ao facto de a data e a hora do computador não estarem corretas. Só reconstrua a base de dados de blocos se tiver a certeza de que a data e a hora do seu computador estão corretas</translation> </message> <message> <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation type="unfinished">O montante da transação é demasiado baixo após a dedução da taxa</translation> + <translation type="unfinished">A quantia da transação é demasiado baixa para enviar após a dedução da taxa</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 erro pode ocorrer se a carteira não foi desligada corretamente e foi carregada da ultima vez usando uma compilação com uma versão mais recente da Berkeley DB. Se sim, por favor use o programa que carregou esta carteira da ultima vez.</translation> + <translation type="unfinished">Este erro pode ocorrer se a carteira não foi desligada corretamente e foi carregada da última vez usando uma compilação com uma versão mais recente da Berkeley DB. Se sim, por favor use o programa que carregou esta carteira da última vez.</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">Isto é uma compilação de teste de pré-lançamento - use por sua conta e risco - não use para mineração ou comércio</translation> + <translation type="unfinished">Esta é uma versão de teste de pré-lançamento - use por sua conta e risco - não use para mineração ou aplicações comerciais</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">Este é a taxa de transação máxima que você paga (em adição à taxa normal) para priorizar evitar gastos parciais sobre seleção de moeda normal.</translation> + <translation type="unfinished">Esta é a taxa de transação máxima que paga (para além da taxa normal) para dar prioridade à prevenção de gastos parciais em detrimento da seleção regular de moedas.</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 é a taxa de transação que poderá descartar, se o troco for menor que o pó a este nÃvel</translation> + <translation type="unfinished">Esta é a taxa de transação que poderá descartar, se o troco for menor que o remanescente a este nÃvel</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> @@ -4146,31 +4222,39 @@ deve ser fornecido.</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">Comprimento total da entrada da versão de rede (%i) excede o comprimento máximo (%i). Reduzir o número ou o tamanho de uacomments.</translation> + <translation type="unfinished">O comprimento total da entrada da versão de rede (%i) excede o comprimento máximo (%i). Reduza o número ou o tamanho de uacomments.</translation> </message> <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <translation type="unfinished">Não é possÃvel reproduzir os blocos. Terá de reconstruir a base de dados 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 "%s" de ficheiro de carteira desconhecido. Por favor, forneça um dos formatos "bdb" ou "sqlite".</translation> + </message> + <message> <source>Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s.</source> - <translation type="unfinished">Categoria especificada no nÃvel de log não suportada %1$s=%2$s. Esperado %1$s=<category>:<loglevel>. Categorias validas: %3$s. NÃveis de log válidos: %4$s.</translation> + <translation type="unfinished">NÃvel de registo especÃfico da categoria não suportado %1$s=%2$s. Esperado %1$s=<categoria>:<nÃvelderegisto>. Categorias válidas: %3$s. NÃveis de registo válidos: %4$s.</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> + <translation type="unfinished">Foi encontrado um formato de base de dados chainstate não suportado. Por favor reinicie com -reindex-chainstate. Isto irá reconstruir a base de dados do estado da cadeia.</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> + <translation type="unfinished">Carteira criada com sucesso. O tipo de carteira antiga está a ser descontinuado e o suporte para a criação e abertura de carteiras antigas será removido no futuro.</translation> </message> <message> <source>Wallet loaded successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future. Legacy wallets can be migrated to a descriptor wallet with migratewallet.</source> - <translation type="unfinished">Carteira carregada com sucesso. As carteiras legadas estão sendo descontinuadas e o suporte para a criação e abertura de carteiras legadas será removido no futuro. Carteiras legadas podem ser migradas para uma carteira com descritor com a ferramenta migratewallet. </translation> + <translation type="unfinished">Carteira carregada com sucesso. O tipo de carteira antiga legada está a ser descontinuado e o suporte para criar e abrir carteiras antigas será removido no futuro. As carteiras antigas podem ser migradas para uma carteira descritora com migratewallet.</translation> + </message> + <message> + <source>Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> + <translation type="unfinished">Aviso: o formato da carteira do ficheiro de dump "%s" não corresponde ao formato especificado na linha de comando "%s".</translation> </message> <message> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <translation type="unfinished">Aviso: chaves privadas detetadas na carteira {%s} com chaves privadas desativadas</translation> + <translation type="unfinished">Aviso: foram detetadas chaves privadas na carteira {%s} com chaves privadas desativadas</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> @@ -4178,11 +4262,11 @@ deve ser fornecido.</translation> </message> <message> <source>Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> - <translation type="unfinished">Testemunhar dados de blocos após 1%d requer validação. Por favor reinicie com -reindex.</translation> + <translation type="unfinished">Os dados da testemunha para blocos após a altura %d requerem validação. Reinicie com -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">Necessita reconstruir a base de dados, utilizando -reindex para voltar ao modo sem poda. Isto irá descarregar novamente a cadeia de blocos completa</translation> + <translation type="unfinished">Tem de reconstruir a base de dados, utilizando -reindex para voltar ao modo sem redução (prune). Isto irá descarregar novamente a cadeia de blocos completa</translation> </message> <message> <source>%s is set very high!</source> @@ -4190,71 +4274,121 @@ deve ser fornecido.</translation> </message> <message> <source>-maxmempool must be at least %d MB</source> - <translation type="unfinished">- máximo do banco de memória deverá ser pelo menos %d MB</translation> + <translation type="unfinished">-maxmempool tem de ser pelo menos %d MB</translation> </message> <message> <source>A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished">Um erro fatal interno occoreu, veja o debug.log para detalhes</translation> + <translation type="unfinished">Ocorreu um erro interno fatal, ver debug.log para mais pormenores</translation> </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation type="unfinished">Não é possÃvel resolver -%s endereço '%s'</translation> + <translation type="unfinished">Não é possÃvel resolver 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> + <translation type="unfinished">Não é possÃvel definir -forcednsseed como true ao definir -dnsseed como false.</translation> </message> <message> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> - <translation type="unfinished">Não é possÃvel ajustar -peerblockfilters sem -blockfilterindex.</translation> + <translation type="unfinished">Não é possÃvel definir -peerblockfilters sem -blockfilterindex.</translation> </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation type="unfinished">Não foi possÃvel escrever na pasta de dados '%s': verifique as permissões.</translation> + <translation type="unfinished">Não foi possÃvel escrever na pasta de dados "%s": verifique as permissões.</translation> + </message> + <message> + <source>%s is set very high! Fees this large could be paid on a single transaction.</source> + <translation type="unfinished">%s é muito elevado! As taxas tão elevadas como esta poderiam ser pagas numa única transação.</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> + <translation type="unfinished">Não é possÃvel fornecer conexões especÃficas e fazer com que o addrman encontre conexões de saÃda 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> + <translation type="unfinished">Erro ao abrir %s: carteira com assinante externo. Não foi compilado suporte para assinantes externos</translation> </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address metadata may be missing or incorrect.</source> - <translation type="unfinished">Erro ao ler arquivo %s! Todas as chaves foram lidas corretamente, mas os dados de transação ou os metadados de endereço podem estar incorretos ou faltando.</translation> + <translation type="unfinished">Erro ao ler o ficheiro %s! Todas as chaves foram lidas corretamente, mas os dados da transação ou os metadados do endereço podem estar em falta ou incorretos.</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> + <translation type="unfinished">Erro: os dados do livro de endereços na carteira não podem ser identificados como pertencentes 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> + <translation type="unfinished">Erro: foram criados descritores duplicados durante a migração. A 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> + <translation type="unfinished">Erro: a transação %s na carteira não pode ser identificada como pertencente a carteiras migradas</translation> </message> <message> <source>Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.</source> - <translation type="unfinished">Falha ao calcular as taxas de colisão porque os UTXOs não confirmados dependem de um enorme conjunto de transações não confirmadas.</translation> + <translation type="unfinished">Não foi possÃvel calcular as taxas de compensação, porque os UTXOs não confirmados dependem de um enorme conjunto de transações não confirmadas..</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> + <translation type="unfinished">Falha ao alterar o nome do ficheiro peers.dat inválido. Mova-o ou elimine-o e tente novamente.</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source> + <translation type="unfinished">A estimativa da taxa falhou. A taxa de retrocesso está desativada. Aguardar alguns blocos ou ativar %s.</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> + <translation type="unfinished">Opções incompatÃveis: "-dnsseed=1" foi explicitamente especificada, mas "-onlynet" proÃbe conexões para IPv4/IPv6</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> + <translation type="unfinished">Quantia inválida para %s=<amount>: '%s' (tem de ser, pelo menos, a taxa mÃnima de retransmissão de %s para evitar transações bloqueadas)</translation> + </message> + <message> + <source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source> + <translation type="unfinished">Conexões de saÃda restritas ao CJDNS (-onlynet=cjdns) mas -cjdnsreachable não é fornecido</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> + <translation type="unfinished">As conexões de saÃda foram restringidas à 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> + <translation type="unfinished">As conexões de saÃda foram restringidas à rede Tor (-onlynet=onion) mas o proxy para aceder à rede Tor não foi fornecido: nenhuma opção "-proxy", "-onion" ou "-listenonion" foi fornecida</translation> + </message> + <message> + <source>Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source> + <translation type="unfinished">Conexões de saÃda restringidas ao i2p (-onlynet=i2p) mas não foi fornecido -i2psam</translation> + </message> + <message> + <source>The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs</source> + <translation type="unfinished">O tamanho das entradas excede o peso máximo. Por favor, tente enviar uma quantia menor ou consolidar manualmente os UTXOs da sua carteira</translation> + </message> + <message> + <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">A quantia total de moedas pré-selecionadas não cobre o objetivo da transação. Permita que sejam selecionadas automaticamente outras entradas ou inclua mais moedas manualmente</translation> + </message> + <message> + <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source> + <translation type="unfinished">A transação requer um destino com montante não-0, uma taxa diferente de 0 ou uma entrada pré-selecionada</translation> + </message> + <message> + <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source> + <translation type="unfinished">Falha na validação do instantâneo UTXO. Reinicie para retomar o descarregamento normal do bloco inicial ou tente carregar um instantâneo diferente.</translation> + </message> + <message> + <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source> + <translation type="unfinished">Estão disponÃveis UTXOs não confirmados, mas gastá-los cria uma cadeia de transações que será rejeitada pelo mempool</translation> + </message> + <message> + <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">Encontrada uma entrada legada inesperada na carteira descritora. A carregar a carteira %s + +A carteira pode ter sido adulterada ou criada com intenções maliciosas. +</translation> </message> <message> <source>Unrecognized descriptor found. Loading wallet %s @@ -4262,9 +4396,9 @@ deve ser fornecido.</translation> 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 + <translation type="unfinished">Encontrado descritor não reconhecido. A carregar a carteira %s -A carteira pode ter sido criada em uma versão mais nova. +A carteira pode ter sido criada numa versão mais recente. Por favor tente atualizar o software para a última versão. </translation> </message> @@ -4272,41 +4406,45 @@ Por favor tente atualizar o software para a última versão. <source> Unable to cleanup failed migration</source> <translation type="unfinished"> -ImpossÃvel limpar a falha de migração</translation> +Não foi possÃvel efetuar a limpeza da migração falhada</translation> </message> <message> <source> Unable to restore backup of wallet.</source> <translation type="unfinished"> -ImpossÃvel restaurar backup da carteira.</translation> +Não foi possÃvel restaurar a cópia de segurança da carteira.</translation> + </message> + <message> + <source>Block verification was interrupted</source> + <translation type="unfinished">A verificação do bloco foi interrompida</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 apenas é aplicada na rede %s quando na secção [%s].</translation> + <translation type="unfinished">A configuração para %s apenas é aplicada na rede %s quando se encontra na secção [%s].</translation> </message> <message> <source>Copyright (C) %i-%i</source> - <translation type="unfinished">Direitos de Autor (C) %i-%i</translation> + <translation type="unfinished">Direitos de autor (C) %i-%i</translation> </message> <message> <source>Corrupted block database detected</source> - <translation type="unfinished">Detetada cadeia de blocos corrompida</translation> + <translation type="unfinished">Detetada base de dados de blocos corrompida</translation> </message> <message> <source>Could not find asmap file %s</source> - <translation type="unfinished">Não foi possÃvel achar o arquivo asmap %s</translation> + <translation type="unfinished">Não foi possÃvel encontrar o ficheiro asmap %s</translation> </message> <message> <source>Could not parse asmap file %s</source> - <translation type="unfinished">Não foi possÃvel analisar o arquivo asmap %s.</translation> + <translation type="unfinished">Não foi possÃvel analisar o ficheiro asmap %s.</translation> </message> <message> <source>Disk space is too low!</source> - <translation type="unfinished">Espaço de disco é muito pouco!</translation> + <translation type="unfinished">O espaço em disco é demasiado pequeno!</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> - <translation type="unfinished">Deseja reconstruir agora a base de dados de blocos.</translation> + <translation type="unfinished">Pretende reconstruir a base de dados de blocos agora?</translation> </message> <message> <source>Done loading</source> @@ -4314,19 +4452,19 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Dump file %s does not exist.</source> - <translation type="unfinished">Arquivo de despejo %s não existe</translation> + <translation type="unfinished">O ficheiro de dump %s não existe</translation> </message> <message> <source>Error committing db txn for wallet transactions removal</source> - <translation type="unfinished">Erro durante commiting db txn para a remoção das transações da carteira.</translation> + <translation type="unfinished">Erro ao confirmar a transação da base de dados para remover transações da carteira</translation> </message> <message> <source>Error creating %s</source> - <translation type="unfinished">Erro a criar %s</translation> + <translation type="unfinished">Erro ao criar %s</translation> </message> <message> <source>Error initializing block database</source> - <translation type="unfinished">Erro ao inicializar a cadeia de blocos</translation> + <translation type="unfinished">Erro ao inicializar a base de dados de blocos</translation> </message> <message> <source>Error initializing wallet database environment %s!</source> @@ -4350,15 +4488,19 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Error loading block database</source> - <translation type="unfinished">Erro ao carregar base de dados de blocos</translation> + <translation type="unfinished">Erro ao carregar a base de dados de blocos</translation> </message> <message> <source>Error opening block database</source> <translation type="unfinished">Erro ao abrir a base de dados de blocos</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">Erro ao ler o ficheiro de configuração: %s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> - <translation type="unfinished">Erro ao ler da base de dados. A encerrar.</translation> + <translation type="unfinished">Erro ao ler a base de dados. A encerrar.</translation> </message> <message> <source>Error reading next record from wallet database</source> @@ -4366,103 +4508,115 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Error starting db txn for wallet transactions removal</source> - <translation type="unfinished">Erro durante o inÃcio db txn para a remoção das transações da carteira.</translation> + <translation type="unfinished">Erro ao iniciar a transação da base de dados para remoção de transações da carteira</translation> + </message> + <message> + <source>Error: Cannot extract destination from the generated scriptpubkey</source> + <translation type="unfinished">Erro: não é possÃvel extrair o destino da scriptpubkey gerada</translation> + </message> + <message> + <source>Error: Couldn't create cursor into database</source> + <translation type="unfinished">Erro: não foi possÃvel criar o cursor na base de dados</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> <message> + <source>Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <translation type="unfinished">Erro: a soma de controlo do ficheiro de dump não corresponde. Calculado %s, esperado %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> + <translation type="unfinished">Erro: falha ao criar uma nova carteira de observação</translation> </message> <message> <source>Error: Got key that was not hex: %s</source> - <translation type="unfinished">Erro: Chave obtida sem ser no formato hex: %s</translation> + <translation type="unfinished">Erro: obteve-se uma chave que não era hexadecimal: %s</translation> </message> <message> <source>Error: Got value that was not hex: %s</source> - <translation type="unfinished">Erro: Valor obtido sem ser no formato hex: %s</translation> + <translation type="unfinished">Erro: obtido um valor que não era hexadecimal: %s</translation> </message> <message> <source>Error: Keypool ran out, please call keypoolrefill first</source> - <translation type="unfinished">A keypool esgotou-se, por favor execute primeiro keypoolrefill1</translation> + <translation type="unfinished">Erro: a pool de chaves esgotou-se. Invoque primeiro keypoolrefill</translation> </message> <message> <source>Error: Missing checksum</source> - <translation type="unfinished">Erro: soma de verificação ausente</translation> + <translation type="unfinished">Erro: falta a soma de controlo / checksum</translation> </message> <message> <source>Error: No %s addresses available.</source> - <translation type="unfinished">Erro: Não existem %s endereços disponÃveis.</translation> + <translation type="unfinished">Erro: não existem endereços %s disponÃveis.</translation> </message> <message> <source>Error: This wallet already uses SQLite</source> - <translation type="unfinished">Erro: Essa carteira já utiliza o SQLite</translation> + <translation type="unfinished">Erro: esta carteira já usa 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> + <translation type="unfinished">Erro: esta carteira já é uma carteira descritora</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> + <translation type="unfinished">Erro: não foi possÃvel iniciar a leitura de todos os registos na base 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> + <translation type="unfinished">Erro: não é possÃvel efetuar uma cópia de segurança da sua carteira</translation> </message> <message> <source>Error: Unable to parse version %u as a uint32_t</source> - <translation type="unfinished">Erro: Não foi possÃvel converter versão %u como uint32_t</translation> + <translation type="unfinished">Erro: não foi possÃvel analisar a versão %u como um 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> + <translation type="unfinished">Erro: não foi possÃvel ler todos os registos na base de dados</translation> </message> <message> <source>Error: Unable to read wallet's best block locator record</source> - <translation type="unfinished">Erro: Não foi possÃvel ler o melhor registo de localização de bloqueio da pasta</translation> + <translation type="unfinished">Erro: não foi possÃvel ler o melhor registo de localização de blocos da carteira</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> + <translation type="unfinished">Erro: não foi possÃvel remover os dados só de observação do livro de endereços</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> + <translation type="unfinished">Erro: não foi possÃvel escrever o registo para a nova carteira</translation> </message> <message> <source>Error: Unable to write solvable wallet best block locator record</source> - <translation type="unfinished">Erro: Não foi possÃvel escrever o registo do melhor localizador de bloqueio da pasta solvÃvel</translation> + <translation type="unfinished">Erro: não foi possÃvel escrever o registo do melhor localizador de blocos da carteira solvente</translation> </message> <message> <source>Error: Unable to write watchonly wallet best block locator record</source> - <translation type="unfinished">Erro: Não é possÃvel escrever o registo do melhor localizador de blocos da pasta watchonly</translation> + <translation type="unfinished">Erro: não foi possÃvel escrever o registo do melhor localizador de blocos da carteira só de observação</translation> </message> <message> <source>Error: address book copy failed for wallet %s</source> - <translation type="unfinished">Erro: falha na cópia da agenda de endereços para a carteira %s</translation> + <translation type="unfinished">Erro: falha na cópia do livro de endereços para a carteira %s</translation> </message> <message> <source>Error: database transaction cannot be executed for wallet %s</source> - <translation type="unfinished">Erro: a transação do banco de dados não pode ser executada para a carteira %s</translation> + <translation type="unfinished">Erro: a transação da base de dados não pode ser executada para a carteira %s</translation> </message> <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation type="unfinished">Falhou a escutar em qualquer porta. Use -listen=0 se quiser isto.</translation> + <translation type="unfinished">Falha ao escutar em qualquer porta. Use -listen=0 se quiser isso.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> - <translation type="unfinished">Reexaminação da carteira falhou durante a inicialização</translation> + <translation type="unfinished">Falha ao verificar novamente a carteira durante a inicialização</translation> </message> <message> <source>Failed to start indexes, shutting down..</source> - <translation type="unfinished">Falha ao iniciar Ãndices, desligando..</translation> + <translation type="unfinished">Falha ao iniciar os Ãndices. A encerrar…</translation> </message> <message> <source>Failed to verify database</source> - <translation type="unfinished">Falha ao verificar base de dados</translation> + <translation type="unfinished">Falha ao verificar a base de dados</translation> </message> <message> <source>Failure removing transaction: %s</source> @@ -4470,11 +4624,11 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> - <translation type="unfinished">A variação da taxa (%s) é menor que a mÃnima variação de taxa (%s) configurada.</translation> + <translation type="unfinished">A taxa de transação (%s) é inferior à taxa mÃnima de transação fixada (%s)</translation> </message> <message> <source>Ignoring duplicate -wallet %s.</source> - <translation type="unfinished">Ignorando -carteira %s duplicada.</translation> + <translation type="unfinished">Ignorando -wallet %s duplicada.</translation> </message> <message> <source>Importing…</source> @@ -4486,23 +4640,27 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Initialization sanity check failed. %s is shutting down.</source> - <translation type="unfinished">Verificação de integridade inicial falhou. O %s está a desligar-se.</translation> + <translation type="unfinished">A verificação da integridade inicial falhou. O %s está a encerrar.</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 dbcache for block verification</source> + <translation type="unfinished">Cache da base de dados (Dbcache) insuficiente para verificação de blocos</translation> + </message> + <message> <source>Insufficient funds</source> <translation type="unfinished">Fundos insuficientes</translation> </message> <message> <source>Invalid -i2psam address or hostname: '%s'</source> - <translation type="unfinished">Endereço ou nome de servidor -i2psam inválido: '%s'</translation> + <translation type="unfinished">Endereço -i2psam ou nome do servidor inválido: '%s'</translation> </message> <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation type="unfinished">Endereço -onion ou hostname inválido: '%s'</translation> + <translation type="unfinished">Endereço -onion ou nome do servidor inválido: '%s'</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> @@ -4510,31 +4668,47 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Invalid P2P permission: '%s'</source> - <translation type="unfinished">Permissões P2P inválidas : '%s'</translation> + <translation type="unfinished">Permissões P2P inválidas: '%s'</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s' (must be at least %s)</source> + <translation type="unfinished">Quantia inválida para %s=<amount>: '%s' (tem de ser pelo menos %s)</translation> + </message> + <message> + <source>Invalid amount for %s=<amount>: '%s'</source> + <translation type="unfinished">Quantia inválida para %s=<amount>: '%s'</translation> </message> <message> <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation type="unfinished">Valor inválido para -%s=<amount>: '%s'</translation> + <translation type="unfinished">Quantia inválida para -%s=<amount>: '%s'</translation> </message> <message> <source>Invalid netmask specified in -whitelist: '%s'</source> <translation type="unfinished">Máscara de rede inválida especificada em -whitelist: '%s'</translation> </message> <message> + <source>Invalid port specified in %s: '%s'</source> + <translation type="unfinished">Porta inválida especificada em %s: '%s'</translation> + </message> + <message> + <source>Invalid pre-selected input %s</source> + <translation type="unfinished">Entrada pré-selecionada %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> + <translation type="unfinished">A escuta de conexões de entrada falhou (a escuta devolveu o erro %s)</translation> </message> <message> <source>Loading P2P addresses…</source> - <translation type="unfinished">Carregando endereços P2P...</translation> + <translation type="unfinished">A carregar endereços P2P…</translation> </message> <message> <source>Loading banlist…</source> - <translation type="unfinished">A carregar a lista de banidos...</translation> + <translation type="unfinished">A carregar a lista de banidos…</translation> </message> <message> <source>Loading block index…</source> - <translation type="unfinished">Carregando Ãndice do bloco...</translation> + <translation type="unfinished">A carregar o Ãndice de blocos…</translation> </message> <message> <source>Loading wallet…</source> @@ -4550,7 +4724,7 @@ ImpossÃvel restaurar backup da carteira.</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> + <translation type="unfinished">É necessário especificar uma porta com -whitebind: '%s'</translation> </message> <message> <source>No addresses available</source> @@ -4558,47 +4732,55 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Not enough file descriptors available.</source> - <translation type="unfinished">Os descritores de ficheiros disponÃveis são insuficientes.</translation> + <translation type="unfinished">Não estão disponÃveis descritores de ficheiros suficientes.</translation> + </message> + <message> + <source>Not found pre-selected input %s</source> + <translation type="unfinished">Entrada pré-selecionada %s não encontrada</translation> + </message> + <message> + <source>Not solvable pre-selected input %s</source> + <translation type="unfinished">Entrada pré-selecionada %s não solucionável</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> - <translation type="unfinished">A redução não pode ser configurada com um valor negativo.</translation> + <translation type="unfinished">A redução (prune) não pode ser configurada com um valor negativo.</translation> </message> <message> <source>Prune mode is incompatible with -txindex.</source> - <translation type="unfinished">O modo de redução é incompatÃvel com -txindex.</translation> + <translation type="unfinished">O modo de redução (prune) é incompatÃvel com -txindex.</translation> </message> <message> <source>Pruning blockstore…</source> - <translation type="unfinished">Prunando os blocos existentes...</translation> + <translation type="unfinished">Prunando os blocos existentes…</translation> </message> <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> - <translation type="unfinished">Reduzindo -maxconnections de %d para %d, devido a limitações no sistema.</translation> + <translation type="unfinished">A reduzir -maxconnections de %d para %d devido a limitações no sistema.</translation> </message> <message> <source>Replaying blocks…</source> - <translation type="unfinished">Repetindo blocos...</translation> + <translation type="unfinished">Repetindo blocos…</translation> </message> <message> <source>Rescanning…</source> - <translation type="unfinished">.Reexaminando...</translation> + <translation type="unfinished">A tornar a examinar…</translation> </message> <message> <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <translation type="unfinished">SQLiteDatabase: Falha ao executar a instrução para verificar o banco de dados: %s</translation> + <translation type="unfinished">SQLiteDatabase: falha na execução da instrução para verificar a base de dados: %s</translation> </message> <message> <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> - <translation type="unfinished">SQLiteDatabase: Falha ao preparar a instrução para verificar o banco de dados: %s</translation> + <translation type="unfinished">SQLiteDatabase: falha ao preparar a instrução para verificar a base de dados: %s</translation> </message> <message> <source>SQLiteDatabase: Failed to read database verification error: %s</source> - <translation type="unfinished">SQLiteDatabase: Falha ao ler base de dados erro de verificação %s</translation> + <translation type="unfinished">SQLiteDatabase: falha na leitura do erro de verificação da base de dados: %s</translation> </message> <message> <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> - <translation type="unfinished">SQLiteDatabase: ID de aplicativo inesperado. Esperado %u, obteve %u</translation> + <translation type="unfinished">SQLiteDatabase: ID de aplicação inesperado. Era esperado %u, obteve-se %u</translation> </message> <message> <source>Section [%s] is not recognized.</source> @@ -4606,7 +4788,7 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Signing transaction failed</source> - <translation type="unfinished">Falhou assinatura da transação</translation> + <translation type="unfinished">Falha ao assinar a transação</translation> </message> <message> <source>Specified -walletdir "%s" does not exist</source> @@ -4622,37 +4804,39 @@ ImpossÃvel restaurar backup da carteira.</translation> </message> <message> <source>Specified blocks directory "%s" does not exist.</source> - <translation type="unfinished"> -A pasta de blocos especificados "%s" não existe.</translation> + <translation type="unfinished">A pasta de blocos especificados "%s" não existe.</translation> + </message> + <message> + <source>Specified data directory "%s" does not exist.</source> + <translation type="unfinished">O diretório de dados especificado "%s" não existe.</translation> </message> <message> <source>Starting network threads…</source> - <translation type="unfinished">A iniciar threads de rede...</translation> + <translation type="unfinished">A iniciar threads de rede…</translation> </message> <message> <source>The source code is available from %s.</source> - <translation type="unfinished">O código fonte está disponÃvel pelo %s.</translation> + <translation type="unfinished">O código-fonte está disponÃvel em %s.</translation> </message> <message> <source>The specified config file %s does not exist</source> - <translation type="unfinished">O ficheiro de configuração especificado %s não existe -</translation> + <translation type="unfinished">O ficheiro de configuração especificado %s não existe</translation> </message> <message> <source>The transaction amount is too small to pay the fee</source> - <translation type="unfinished">O montante da transação é demasiado baixo para pagar a taxa</translation> + <translation type="unfinished">A quantia da transação é demasiado baixa para pagar a taxa</translation> </message> <message> <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation type="unfinished">A carteira evitará pagar menos que a taxa minima de propagação.</translation> + <translation type="unfinished">A carteira evitará pagar menos do que a taxa mÃnima de retransmissão.</translation> </message> <message> <source>This is experimental software.</source> - <translation type="unfinished">Isto é software experimental.</translation> + <translation type="unfinished">Isto é um software experimental.</translation> </message> <message> <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation type="unfinished">Esta é a taxa minima de transação que paga em cada transação.</translation> + <translation type="unfinished">Esta é a taxa mÃnima de transação que paga em cada transação.</translation> </message> <message> <source>This is the transaction fee you will pay if you send a transaction.</source> @@ -4660,19 +4844,19 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Transaction %s does not belong to this wallet</source> - <translation type="unfinished">A transação %s não pertence a esta carteira.</translation> + <translation type="unfinished">A transação %s não pertence a esta carteira</translation> </message> <message> <source>Transaction amount too small</source> - <translation type="unfinished">Quantia da transação é muito baixa</translation> + <translation type="unfinished">Quantia da transação demasiado baixa</translation> </message> <message> <source>Transaction amounts must not be negative</source> - <translation type="unfinished">Os valores da transação não devem ser negativos</translation> + <translation type="unfinished">As quantias das transações não devem 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> + <translation type="unfinished">O Ãndice de saÃdas de troca de transações está fora do alcance</translation> </message> <message> <source>Transaction must have at least one recipient</source> @@ -4680,23 +4864,23 @@ A pasta de blocos especificados "%s" não existe.</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> + <translation type="unfinished">A transação precisa de um endereço de troco, mas não o conseguimos gerar.</translation> </message> <message> <source>Transaction too large</source> - <translation type="unfinished">Transação grande demais</translation> + <translation type="unfinished">Transação demasiado 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> + <translation type="unfinished">Não foi possÃvel atribuir memória para -maxsigcachesize: '%s' MiB</translation> </message> <message> <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation type="unfinished">Incapaz de vincular à porta %s neste computador (vÃnculo retornou erro %s)</translation> + <translation type="unfinished">Não foi possÃvel vincular a %s neste computador (a vinculação devolveu o erro %s)</translation> </message> <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> - <translation type="unfinished">ImpossÃvel associar a %s neste computador. %s provavelmente já está em execução.</translation> + <translation type="unfinished">Não foi possÃvel vincular a %s neste computador. %s provavelmente já está em execução.</translation> </message> <message> <source>Unable to create the PID file '%s': %s</source> @@ -4704,11 +4888,11 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Unable to find UTXO for external input</source> - <translation type="unfinished">ImpossÃvel localizar e entrada externa UTXO</translation> + <translation type="unfinished">Não é possÃvel encontrar UTXO para a entrada externa</translation> </message> <message> <source>Unable to generate initial keys</source> - <translation type="unfinished">Incapaz de gerar as chaves iniciais</translation> + <translation type="unfinished">Não foi possÃvel gerar as chaves iniciais</translation> </message> <message> <source>Unable to generate keys</source> @@ -4724,23 +4908,23 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Unable to start HTTP server. See debug log for details.</source> - <translation type="unfinished">Não é possÃvel iniciar o servidor HTTP. Verifique o debug.log para detalhes.</translation> + <translation type="unfinished">Não é possÃvel iniciar o servidor HTTP. Consulte o registo de depuração para obter detalhes.</translation> </message> <message> <source>Unable to unload the wallet before migrating</source> - <translation type="unfinished">ImpossÃvel desconectar carteira antes de migrá-la</translation> + <translation type="unfinished">Não foi possÃvel desconectar a carteira antes de a migrar</translation> </message> <message> <source>Unknown -blockfilterindex value %s.</source> - <translation type="unfinished">Desconhecido -blockfilterindex valor %s.</translation> + <translation type="unfinished">Valor %s de -blockfilterindex desconhecido.</translation> </message> <message> <source>Unknown address type '%s'</source> - <translation type="unfinished">Tipo de endereço desconhecido '%s'</translation> + <translation type="unfinished">Tipo de endereço desconhecido: "%s"</translation> </message> <message> <source>Unknown change type '%s'</source> - <translation type="unfinished">Tipo de mudança desconhecido '%s'</translation> + <translation type="unfinished">Tipo de troco desconhecido: "%s"</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> @@ -4756,7 +4940,7 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Wallet file creation failed: %s</source> - <translation type="unfinished">falha na criação do ficheiro da pasta: %s</translation> + <translation type="unfinished">Falha na criação do ficheiro da carteira: %s</translation> </message> <message> <source>acceptstalefeeestimates is not supported on %s chain.</source> @@ -4764,19 +4948,19 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> - <translation type="unfinished">Categoria de registos desconhecida %s=%s.</translation> + <translation type="unfinished">Categoria de registo não suportada %s=%s.</translation> </message> <message> <source>Error: Could not add watchonly tx %s to watchonly wallet</source> - <translation type="unfinished">Erro: Não foi possÃvel adicionar tx %s de vigilância à pasta de vigilância</translation> + <translation type="unfinished">Erro: não foi possÃvel adicionar a transação só de observação %s à carteira de observaçã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> + <translation type="unfinished">Erro: não foi possÃvel eliminar transações só de observação.</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> + <translation type="unfinished">O comentário no agente do utilizador/user agent (%s) contém caracteres inseguros.</translation> </message> <message> <source>Verifying blocks…</source> @@ -4788,7 +4972,7 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation type="unfinished">A carteira precisou de ser reescrita: reinicie %s para completar</translation> + <translation type="unfinished">Foi necessário reescrever a carteira: reinicie %s para concluir</translation> </message> <message> <source>Settings file could not be read</source> @@ -4796,7 +4980,7 @@ A pasta de blocos especificados "%s" não existe.</translation> </message> <message> <source>Settings file could not be written</source> - <translation type="unfinished">Não foi possÃvel editar o ficheiro de configurações</translation> + <translation type="unfinished">Não foi possÃvel escrever o ficheiro de configurações</translation> </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 33a9c23d75..02debe791f 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -95,11 +95,11 @@ Só é possÃvel assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>Sending addresses - %1</source> - <translation type="unfinished">Enviando endereços - %1</translation> + <translation type="unfinished">Endereços de envio - %1</translation> </message> <message> <source>Receiving addresses - %1</source> - <translation type="unfinished">Recebendo endereços - %1</translation> + <translation type="unfinished">Endereços de recebimento - %1</translation> </message> <message> <source>Exporting Failed</source> @@ -2253,7 +2253,7 @@ O processo de migração criará um backup da carteira antes da migração. Este </message> <message> <source>Mapped AS</source> - <translation type="unfinished">Mapeado como</translation> + <translation type="unfinished">S.A. de mapeamento</translation> </message> <message> <source>Whether we relay addresses to this peer.</source> diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts index 059436329d..0bb08f5c1e 100644 --- a/src/qt/locale/bitcoin_ro.ts +++ b/src/qt/locale/bitcoin_ro.ts @@ -225,6 +225,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Parola portofelului a fost schimbata.</translation> </message> <message> + <source>Passphrase change failed</source> + <translation type="unfinished">Schimbarea frazei de acces a esuat</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">AtenÅ£ie! Caps Lock este pornit!</translation> </message> @@ -365,6 +369,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <numerusform /> </translation> </message> + <message> + <source>%1 kB</source> + <translation type="unfinished">%1kB</translation> + </message> </context> <context> <name>BitcoinGUI</name> @@ -417,6 +425,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Crează un portofel nou</translation> </message> <message> + <source>&Minimize</source> + <translation type="unfinished">&Reduce</translation> + </message> + <message> <source>Wallet:</source> <translation type="unfinished">Portofel:</translation> </message> @@ -598,10 +610,18 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Actualizat</translation> </message> <message> + <source>Ctrl+Q</source> + <translation type="unfinished">Ctr+Q</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction</source> <translation type="unfinished">ÃŽncărcaÈ›i TranzacÈ›ia Bitcoin ParÈ›ial Semnată</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Incarca PSBT din &notite</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">ÃŽncărcaÈ›i TranzacÈ›ia Bitcoin ParÈ›ial Semnată din clipboard</translation> </message> @@ -638,10 +658,28 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Inchide portofel</translation> </message> <message> + <source>Restore Wallet…</source> + <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment> + <translation type="unfinished">Recupereaza Portofelul...</translation> + </message> + <message> + <source>Restore a wallet from a backup file</source> + <extracomment>Status tip for Restore Wallet menu item</extracomment> + <translation type="unfinished">Recupereaza Portofelul din fisierele rezerva</translation> + </message> + <message> <source>Close all wallets</source> <translation type="unfinished">ÃŽnchideÈ›i toate portofelele</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Transfera Portofelul</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Transfera un portofel</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation type="unfinished">Arată mesajul de ajutor %1 pentru a obÅ£ine o listă cu opÅ£iunile posibile de linii de comandă Bitcoin</translation> </message> @@ -686,6 +724,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">&Fereastră</translation> </message> <message> + <source>Ctrl+M</source> + <translation type="unfinished">Ctr+M</translation> + </message> + <message> <source>Main Window</source> <translation type="unfinished">Fereastra principală</translation> </message> @@ -693,6 +735,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <source>%1 client</source> <translation type="unfinished">Client %1</translation> </message> + <message> + <source>&Hide</source> + <translation type="unfinished">&Ascunde</translation> + </message> + <message> + <source>S&how</source> + <translation type="unfinished">A&rata</translation> + </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> @@ -708,6 +758,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Pulsează pentru mai multe acÈ›iuni.</translation> </message> <message> + <source>Error creating wallet</source> + <translation type="unfinished">Eroare creare portofel</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Eroare: %1</translation> </message> @@ -862,6 +916,22 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Copiază suma</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Copiaza adresa</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Copiaza si eticheteaza</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">copiaza &valoarea</translation> + </message> + <message> + <source>Copy transaction &ID and output index</source> + <translation type="unfinished">copiaza ID-ul de tranzactie si indexul de iesire</translation> + </message> + <message> <source>Copy quantity</source> <translation type="unfinished">Copiază cantitea</translation> </message> @@ -910,6 +980,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Crează portofel</translation> </message> <message> + <source>Creating Wallet <b>%1</b>…</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">Creeaza Protofel<b>%1</b></translation> + </message> + <message> <source>Create wallet failed</source> <translation type="unfinished">Crearea portofelului a eÅŸuat</translation> </message> @@ -932,6 +1007,29 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Muta portofelul</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Esti sigur ca vrei sa muti portofelul <i>%1</i>?</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Transfera Portofelul</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">Mutare esuata</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">Mutarea s-a efectuat cu succes</translation> + </message> +</context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -1004,6 +1102,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Crează portofel</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Esti la un pas distanta pentru a-ti crea noul tau portofel!</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Numele portofelului</translation> </message> @@ -1248,6 +1350,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <context> <name>ShutdownWindow</name> <message> + <source>%1 is shutting down…</source> + <translation type="unfinished">%1 se închide</translation> + </message> + <message> <source>Do not shut down the computer until this window disappears.</source> <translation type="unfinished">Nu închide calculatorul pînă ce această fereastră nu dispare.</translation> </message> @@ -1554,6 +1660,13 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> </message> </context> <context> + <name>OptionsModel</name> + <message> + <source>Could not read setting "%1", %2.</source> + <translation type="unfinished">nu s-a putut citi setarea "%1", %2</translation> + </message> +</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> @@ -1635,6 +1748,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Inchide</translation> </message> <message> + <source>Failed to load transaction: %1</source> + <translation type="unfinished">Nu s-a reusit incarcarea tranzactiei: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation type="unfinished">Nu s-a reusit semnarea tranzactiei: %1</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">SalvaÈ›i datele tranzacÈ›iei</translation> </message> @@ -1643,6 +1764,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">adresa proprie</translation> </message> <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation type="unfinished">Nu s-a putut calcula comisionul de tranzactie sau suma totala al tranzactiei.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation type="unfinished">Plateste comisionul de tranzactie: </translation> + </message> + <message> <source>Total Amount</source> <translation type="unfinished">Suma totală</translation> </message> @@ -1690,6 +1819,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Agent utilizator</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">Ani</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">DirecÅ£ie</translation> @@ -1733,6 +1867,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <context> <name>QRImageWidget</name> <message> + <source>&Save Image…</source> + <translation type="unfinished">&Salveaza Imaginea...</translation> + </message> + <message> <source>&Copy Image</source> <translation type="unfinished">&Copiaza Imaginea</translation> </message> @@ -1752,7 +1890,12 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <source>Save QR Code</source> <translation type="unfinished">Salvează codul 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">Imagine PNG</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> @@ -1836,6 +1979,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">SelectaÅ£i un partener pentru a vedea informaÅ£iile detaliate.</translation> </message> <message> + <source>Session ID</source> + <translation type="unfinished">ID-ul Sesiunii</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Versiune</translation> </message> @@ -1852,6 +1999,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Blocuri Sincronizate</translation> </message> <message> + <source>Last Transaction</source> + <translation type="unfinished">Ultima Tranzactie</translation> + </message> + <message> <source>User Agent</source> <translation type="unfinished">Agent utilizator</translation> </message> @@ -1872,6 +2023,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Mareste fontul</translation> </message> <message> + <source>Permissions</source> + <translation type="unfinished">Permisiuni</translation> + </message> + <message> + <source>Direction/Type</source> + <translation type="unfinished">Directie/Tip</translation> + </message> + <message> <source>Services</source> <translation type="unfinished">Servicii</translation> </message> @@ -1940,6 +2099,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">IeÅŸire:</translation> </message> <message> + <source>&Copy address</source> + <extracomment>Context menu action to copy the address of a peer.</extracomment> + <translation type="unfinished">&Copiaza adresa</translation> + </message> + <message> <source>&Disconnect</source> <translation type="unfinished">&Deconectare</translation> </message> @@ -1964,6 +2128,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Executarea comenzii fara nici un portofel.</translation> </message> <message> + <source>Ctrl+I</source> + <translation type="unfinished">Ctrl+l</translation> + </message> + <message> <source>Executing command using "%1" wallet</source> <translation type="unfinished">Executarea comenzii folosind portofelul "%1"</translation> </message> @@ -1988,6 +2156,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Interzicere pentru</translation> </message> <message> + <source>Never</source> + <translation type="unfinished">Niciodata</translation> + </message> + <message> <source>Unknown</source> <translation type="unfinished">Necunoscut</translation> </message> @@ -2055,6 +2227,18 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Copiază &URl</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Copiaza adresa</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Copiaza si eticheteaza</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">copiaza &valoarea</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation type="unfinished">Portofelul nu a putut fi deblocat.</translation> </message> @@ -2086,6 +2270,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Copiază &adresa</translation> </message> <message> + <source>&Verify</source> + <translation type="unfinished">&Verifica</translation> + </message> + <message> + <source>&Save Image…</source> + <translation type="unfinished">&Salveaza Imaginea...</translation> + </message> + <message> <source>Payment information</source> <translation type="unfinished">InformaÅ£iile plată</translation> </message> @@ -2216,6 +2408,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Åžterge toate câmpurile formularului.</translation> </message> <message> + <source>Choose…</source> + <translation type="unfinished">Alege...</translation> + </message> + <message> <source>Confirmation time target:</source> <translation type="unfinished">Timp confirmare tinta:</translation> </message> @@ -2276,6 +2472,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">%1 la %2</translation> </message> <message> + <source>Sign failed</source> + <translation type="unfinished">Semnatura esuata</translation> + </message> + <message> <source>Save Transaction Data</source> <translation type="unfinished">SalvaÈ›i datele tranzacÈ›iei</translation> </message> @@ -2858,6 +3058,31 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Suma minimă</translation> </message> <message> + <source>&Copy address</source> + <translation type="unfinished">&Copiaza adresa</translation> + </message> + <message> + <source>Copy &label</source> + <translation type="unfinished">Copiaza si eticheteaza</translation> + </message> + <message> + <source>Copy &amount</source> + <translation type="unfinished">copiaza &valoarea</translation> + </message> + <message> + <source>Copy transaction &ID</source> + <translation type="unfinished">Copiaza ID-ul de tranzactie</translation> + </message> + <message> + <source>Copy full transaction &details</source> + <translation type="unfinished">Copiaza toate detaliile tranzacÅ£iei</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">Arata in %1</translation> + </message> + <message> <source>Export Transaction History</source> <translation type="unfinished">Export istoric tranzacÅ£ii</translation> </message> @@ -2918,6 +3143,14 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <context> <name>WalletFrame</name> <message> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation type="unfinished">Nu a fost incarcat nici un portofel. +Mergi la Fisiere>Deschide Portofel ca sa incarci un portofel. +-SAU-</translation> + </message> + <message> <source>Create a new wallet</source> <translation type="unfinished">Crează un portofel nou</translation> </message> @@ -2925,6 +3158,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <source>Error</source> <translation type="unfinished">Eroare</translation> </message> + <message> + <source>Load Transaction Data</source> + <translation type="unfinished">Incarca datele tranzactiei</translation> + </message> </context> <context> <name>WalletModel</name> @@ -2962,6 +3199,11 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Confirma cresterea comisionului</translation> </message> <message> + <source>Copied to clipboard</source> + <comment>Fee-bump PSBT saved</comment> + <translation type="unfinished">Copiat in Notite</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation type="unfinished">Nu s-a reuÅŸit semnarea tranzacÅ£iei</translation> </message> @@ -2970,6 +3212,10 @@ Semnarea este posibilă numai cu adrese de tip "legacy".</translation> <translation type="unfinished">Tranzactia nu a putut fi consemnata.</translation> </message> <message> + <source>Can't display address</source> + <translation type="unfinished">Nu se poate afisa adresa</translation> + </message> + <message> <source>default wallet</source> <translation type="unfinished">portofel implicit</translation> </message> diff --git a/src/qt/locale/bitcoin_sl.ts b/src/qt/locale/bitcoin_sl.ts index ceae34b731..a9a8cef968 100644 --- a/src/qt/locale/bitcoin_sl.ts +++ b/src/qt/locale/bitcoin_sl.ts @@ -730,6 +730,10 @@ Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> <translation type="unfinished">Predsinhronizacija zaglavij (%1 %)...</translation> </message> <message> + <source>Error creating wallet</source> + <translation type="unfinished">Napaka pri ustvarjanju denarnice</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Napaka: %1</translation> </message> @@ -4212,6 +4216,10 @@ Obnovitev varnostne kopije denarnice ni bila mogoÄa.</translation> <translation type="unfinished">Napaka pri odpiranju podatkovne baze blokov</translation> </message> <message> + <source>Error reading configuration file: %s</source> + <translation type="unfinished">Napaka pri branju nastavitvene datoteke: 1%s</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation type="unfinished">Napaka pri branju iz podarkovne baze, zapiram.</translation> </message> diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 5646cf7938..bfd805fd4a 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -224,6 +224,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Лозинка коју Ñте унели за дешифровање новчаника је погрешна.</translation> </message> <message> + <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">ПриÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñамо Ñа знаковима до — али не укључујући — првог нултог знака. Ðко је ово уÑпешно, поÑтавите нову приÑтупну фразу да биÑте избегли овај проблем у будућноÑти.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">Лозинка новчаника уÑпешно је промењена.</translation> </message> @@ -232,6 +236,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Promena lozinke nije uspela</translation> </message> <message> + <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">Стара приÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñа Ñамо знаковима до — али не укључујући — првог нултог знака.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Упозорање Caps Lock дугме укључено!</translation> </message> @@ -250,6 +258,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> @@ -638,6 +650,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Учитај â€PSBT†из привремене меморије</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију из clipboard-a</translation> </message> @@ -716,6 +732,11 @@ 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>Restore Wallet</source> <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> <translation type="unfinished">Поврати Ðовчаник</translation> diff --git a/src/qt/locale/bitcoin_sr@ijekavianlatin.ts b/src/qt/locale/bitcoin_sr@ijekavianlatin.ts index a10aa71c10..b4558fe4c4 100644 --- a/src/qt/locale/bitcoin_sr@ijekavianlatin.ts +++ b/src/qt/locale/bitcoin_sr@ijekavianlatin.ts @@ -224,6 +224,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Лозинка коју Ñте унели за дешифровање новчаника је погрешна.</translation> </message> <message> + <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">ПриÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñамо Ñа знаковима до — али не укључујући — првог нултог знака. Ðко је ово уÑпешно, поÑтавите нову приÑтупну фразу да биÑте избегли овај проблем у будућноÑти.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">Pristupna fraza novÄanika je uspeÅ¡no promenjena.</translation> </message> @@ -232,6 +236,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Promena lozinke nije uspela</translation> </message> <message> + <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">Стара приÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñа Ñамо знаковима до — али не укључујући — првог нултог знака.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Upozorenje: Caps Lock je ukljuÄen!</translation> </message> @@ -246,6 +254,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> @@ -634,6 +646,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Учитај â€PSBT†из привремене меморије</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију из clipboard-a</translation> </message> @@ -712,6 +728,11 @@ 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>Restore Wallet</source> <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> <translation type="unfinished">Поврати Ðовчаник</translation> diff --git a/src/qt/locale/bitcoin_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts index c7b80f3b02..c596202a49 100644 --- a/src/qt/locale/bitcoin_sr@latin.ts +++ b/src/qt/locale/bitcoin_sr@latin.ts @@ -224,6 +224,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Pristupna fraza za dekriptovanje novÄanika nije taÄna.</translation> </message> <message> + <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">ПриÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñамо Ñа знаковима до — али не укључујући — првог нултог знака. Ðко је ово уÑпешно, поÑтавите нову приÑтупну фразу да биÑте избегли овај проблем у будућноÑти.</translation> + </message> + <message> <source>Wallet passphrase was successfully changed.</source> <translation type="unfinished">Pristupna fraza novÄanika je uspeÅ¡no promenjena.</translation> </message> @@ -232,6 +236,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Promena lozinke nije uspela</translation> </message> <message> + <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">Стара приÑтупна фраза унета за дешифровање новчаника је нетачна. Садржи нулти карактер (тј. - нулти бајт). Ðко је приÑтупна фраза поÑтављена Ñа верзијом овог Ñофтвера Ñтаријом од 25.0, покушајте поново Ñа Ñамо знаковима до — али не укључујући — првог нултог знака.</translation> + </message> + <message> <source>Warning: The Caps Lock key is on!</source> <translation type="unfinished">Upozorenje: Caps Lock je ukljuÄen!</translation> </message> @@ -246,6 +254,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> @@ -634,6 +646,10 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију</translation> </message> <message> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished">Учитај â€PSBT†из привремене меморије</translation> + </message> + <message> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished">Учитај делимично потпиÑану Bitcoin транÑакцију из clipboard-a</translation> </message> @@ -712,6 +728,11 @@ 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>Restore Wallet</source> <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> <translation type="unfinished">Поврати Ðовчаник</translation> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 19903798dd..618a3acbb0 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -1397,6 +1397,10 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</translation> <translation type="unfinished">Denna första synkronisering är väldigt krävande, och kan pÃ¥visa hÃ¥rdvaruproblem hos din dator som tidigare inte visat sig. Varje gÃ¥ng du kör %1, kommer nerladdningen att fortsätta där den avslutades.</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">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 tidigaste transaktionerna %3 när %4 först startades.</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">Om du valt att begränsa storleken pÃ¥ blockkedjan (gallring), mÃ¥ste historiska data ändÃ¥ laddas ner och behandlas, men kommer därefter att tas bort för att spara lagringsutrymme.</translation> </message> @@ -1481,7 +1485,15 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</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 synkroniserar. Den kommer att ladda ner metadata och block frÃ¥n noder och validera dem fram tills att toppen pÃ¥ blockkedjan är nÃ¥dd.</translation> </message> - </context> + <message> + <source>Unknown. Syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Okänd. Synkar huvuden (%1, %2%)...</translation> + </message> + <message> + <source>Unknown. Pre-syncing Headers (%1, %2%)…</source> + <translation type="unfinished">Okänd. För-synkar rubriker (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> @@ -1513,6 +1525,10 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</translation> <translation type="unfinished">&Starta %1 vid 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 av ansning reducerar diskutrymmet som behövs för att lagra transaktioner. Alla block är fortfarande fullt validerade. Inaktivering av denna funktion betyder att hela blockkedjan mÃ¥ste laddas ner pÃ¥ nytt.</translation> + </message> + <message> <source>Size of &database cache</source> <translation type="unfinished">Storleken pÃ¥ &databascache</translation> </message> @@ -1521,6 +1537,10 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</translation> <translation type="unfinished">Antalet skript&verifikationstrÃ¥dar</translation> </message> <message> + <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">Hela sökvägen till ett %1 kompatibelt script (t,ex. C:\Downloads\hwi.exe eller /Users/du/Downloads/hwi.py). Varning: Skadlig programvara kan stjäla dina mynt!</translation> + </message> + <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished">Proxyns IP-adress (t.ex. IPv4: 127.0.0.1 / IPv6: ::1)</translation> </message> @@ -1537,6 +1557,10 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</translation> <translation type="unfinished">Typsnitt pÃ¥ översiktsfliken:</translation> </message> <message> + <source>Options set in this dialog are overridden by the command line:</source> + <translation type="unfinished">Alternativ som anges i denna dialog Ã¥sidosätts av kommandoraden:</translation> + </message> + <message> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished">Öppna konfigurationsfilen %1 frÃ¥n arbetskatalogen.</translation> </message> @@ -1565,10 +1589,25 @@ Om den här plÃ¥nboken innehÃ¥ller lösbara</translation> <translation type="unfinished">Vid avstängning av denna inställning kommer den fullständiga blockkedjan behövas laddas ned 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">Maximal storlek för databasens cacheminne. Större cache kan bidra till snabbare synkronisering, dock blir fördelen mindre uppenbar för de flesta användningsomrÃ¥dena efter den initiala synkroniseringen. En lägre storlek pÃ¥ databasens cacheminne minskar minnesanvändningen. Mempoolens outnyttjade minne delas med denna 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">Sätt antalet trÃ¥dar för skriptverifiering. Negativa värden motsvarar antalet kärnor som skall lämnas tillgängliga för systemet. </translation> + </message> + <message> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished">(0 = auto, <0 = lämna sÃ¥ mÃ¥nga kärnor lediga)</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">Detta tillÃ¥ter dig eller ett tredjepartsverktyg att kommunicera med noden genom kommandotolken och JSON-RPC-kommandon. </translation> + </message> + <message> <source>Enable R&PC server</source> <extracomment>An Options window setting to enable the RPC server.</extracomment> <translation type="unfinished">Aktivera R&PC-server</translation> diff --git a/src/qt/locale/bitcoin_sw.ts b/src/qt/locale/bitcoin_sw.ts index 499eb68538..e084f3df88 100644 --- a/src/qt/locale/bitcoin_sw.ts +++ b/src/qt/locale/bitcoin_sw.ts @@ -357,6 +357,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <translation type="unfinished">Kuhusu &Qt</translation> </message> <message> + <source>Show information about Qt</source> + <translation type="unfinished">Onyesha habari kuhusu Qt</translation> + </message> + <message> <source>Modify configuration options for %1</source> <translation type="unfinished">Badilisha chaguo za usanidi kwa %1</translation> </message> @@ -398,6 +402,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <translation type="unfinished">&TUMA</translation> </message> <message> + <source>&Receive</source> + <translation type="unfinished">&Pokea</translation> + </message> + <message> <source>&Options…</source> <translation type="unfinished">&Chaguo...</translation> </message> @@ -497,10 +505,38 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> </translation> </message> <message> + <source>Transactions after this will not yet be visible.</source> + <translation type="unfinished">Shughuli baada ya hii bado hazitaonekana.</translation> + </message> + <message> + <source>Error</source> + <translation type="unfinished">Onyo</translation> + </message> + <message> + <source>Warning</source> + <translation type="unfinished">Onyo</translation> + </message> + <message> + <source>Information</source> + <translation type="unfinished">Habari</translation> + </message> + <message> + <source>Open Wallet</source> + <translation type="unfinished">Fungua Pochi</translation> + </message> + <message> + <source>Close wallet</source> + <translation type="unfinished">Funga Pochi</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">Jina la Wallet</translation> </message> + <message> + <source>&Hide</source> + <translation type="unfinished">&Ficha</translation> + </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network.</source> <extracomment>A substring of the tooltip.</extracomment> @@ -526,6 +562,18 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <translation type="unfinished">Wingi</translation> </message> <message> + <source>Amount:</source> + <translation type="unfinished">Kiasi:</translation> + </message> + <message> + <source>Fee:</source> + <translation type="unfinished">Ada:</translation> + </message> + <message> + <source>After Fee:</source> + <translation type="unfinished">Baada ya Ada</translation> + </message> + <message> <source>Received with label</source> <translation type="unfinished">Imepokelewa na chapa</translation> </message> @@ -539,6 +587,14 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</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">Fungua Pochi</translation> + </message> + </context> +<context> <name>RestoreWalletActivity</name> <message> <source>Restore wallet warning</source> @@ -549,6 +605,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <context> <name>WalletController</name> <message> + <source>Close wallet</source> + <translation type="unfinished">Funga Pochi</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">Kufunga pochi kwa muda mrefu sana kunaweza kusababisha kusawazisha tena mnyororo mzima ikiwa upogoaji umewezeshwa.</translation> </message> @@ -657,6 +717,17 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <numerusform /> </translation> </message> + <message> + <source>Error</source> + <translation type="unfinished">Onyo</translation> + </message> + </context> +<context> + <name>OptionsDialog</name> + <message> + <source>Error</source> + <translation type="unfinished">Onyo</translation> + </message> </context> <context> <name>PeerTableModel</name> @@ -699,6 +770,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <context> <name>ReceiveRequestDialog</name> <message> + <source>Amount:</source> + <translation type="unfinished">Kiasi:</translation> + </message> + <message> <source>Label:</source> <translation type="unfinished">Chapa:</translation> </message> @@ -724,6 +799,18 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <source>Quantity:</source> <translation type="unfinished">Wingi</translation> </message> + <message> + <source>Amount:</source> + <translation type="unfinished">Kiasi:</translation> + </message> + <message> + <source>Fee:</source> + <translation type="unfinished">Ada:</translation> + </message> + <message> + <source>After Fee:</source> + <translation type="unfinished">Baada ya Ada</translation> + </message> <message numerus="yes"> <source>Estimated to begin confirmation within %n block(s).</source> <translation type="unfinished"> @@ -818,6 +905,10 @@ Kutia sahihi kunawezekana tu kwa anwani za aina ya 'urithi'.</translation> <source>Create a new wallet</source> <translation type="unfinished">Unda mkoba mpya</translation> </message> + <message> + <source>Error</source> + <translation type="unfinished">Onyo</translation> + </message> </context> <context> <name>WalletView</name> diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index ba3ecca680..7f90dd22de 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -661,6 +661,14 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Tüm cüzdanları kapat</translation> </message> <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Cüzdanı Taşı</translation> + </message> + <message> + <source>Migrate a wallet</source> + <translation type="unfinished">Bir Cüzdanı Taşı</translation> + </message> + <message> <source>&Mask values</source> <translation type="unfinished">& DeÄŸerleri maskele</translation> </message> @@ -752,6 +760,10 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Ãœstbilgiler senkronize ediliyor (%1%)...</translation> </message> <message> + <source>Error creating wallet</source> + <translation type="unfinished">Cüzdan oluÅŸturulurken hata meydana geldi</translation> + </message> + <message> <source>Error: %1</source> <translation type="unfinished">Hata: %1</translation> </message> @@ -1001,6 +1013,37 @@ Cüzdan kilidini aç.</translation> </message> </context> <context> + <name>MigrateWalletActivity</name> + <message> + <source>Migrate wallet</source> + <translation type="unfinished">Cüzdanı taşı</translation> + </message> + <message> + <source>Are you sure you wish to migrate the wallet <i>%1</i>?</source> + <translation type="unfinished">Cüzdanı taşımak istediÄŸine emin misin <i>%1</i>?</translation> + </message> + <message> + <source>Migrate Wallet</source> + <translation type="unfinished">Cüzdanı Taşı</translation> + </message> + <message> + <source>Migrating Wallet <b>%1</b>…</source> + <translation type="unfinished">Cüzdan Taşınıyor <b>%1</b>...</translation> + </message> + <message> + <source>The wallet '%1' was migrated successfully.</source> + <translation type="unfinished">Cüzdan '%1' baÅŸarıyla taşındı.</translation> + </message> + <message> + <source>Migration failed</source> + <translation type="unfinished">Taşıma baÅŸarısız oldu.</translation> + </message> + <message> + <source>Migration Successful</source> + <translation type="unfinished">Taşıma BaÅŸarılı</translation> + </message> +</context> +<context> <name>OpenWalletActivity</name> <message> <source>Open wallet failed</source> @@ -1083,6 +1126,14 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Cüzdan OluÅŸtur</translation> </message> <message> + <source>You are one step away from creating your new wallet!</source> + <translation type="unfinished">Yeni cüzdanını yaratmaktan bir adım uzaktasın!</translation> + </message> + <message> + <source>Please provide a name and, if desired, enable any advanced options</source> + <translation type="unfinished">Lütfen bir isim saÄŸla ve, isteÄŸe baÄŸlı olarak, geliÅŸmiÅŸ seçenekleri etkinleÅŸtir.</translation> + </message> + <message> <source>Wallet Name</source> <translation type="unfinished">Cüzdan Ä°smi</translation> </message> @@ -2056,10 +2107,18 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Ayrıntılı bilgi görmek için bir eÅŸ seçin.</translation> </message> <message> + <source>The transport layer version: %1</source> + <translation type="unfinished">Taşıma katmanı versiyonu: %1</translation> + </message> + <message> <source>Transport</source> <translation type="unfinished">Aktar</translation> </message> <message> + <source>Session ID</source> + <translation type="unfinished">Oturum ID</translation> + </message> + <message> <source>Version</source> <translation type="unfinished">Sürüm</translation> </message> @@ -2226,6 +2285,21 @@ Cüzdan kilidini aç.</translation> <translation type="unfinished">Dışarı:</translation> </message> <message> + <source>detecting: peer could be v1 or v2</source> + <extracomment>Explanatory text for "detecting" transport type.</extracomment> + <translation type="unfinished">keÅŸfediliyor: eÅŸ v1 veya v2 olabilir</translation> + </message> + <message> + <source>v1: unencrypted, plaintext transport protocol</source> + <extracomment>Explanatory text for v1 transport type.</extracomment> + <translation type="unfinished">v1: ÅŸifrelenmemiÅŸ, açık metin taşıma protokolü</translation> + </message> + <message> + <source>v2: BIP324 encrypted transport protocol</source> + <extracomment>Explanatory text for v2 transport type.</extracomment> + <translation type="unfinished">v2: BIP324 ÅŸifrelenmiÅŸ taşıma protokolü</translation> + </message> + <message> <source>&Copy address</source> <extracomment>Context menu action to copy the address of a peer.</extracomment> <translation type="unfinished">&Adresi kopyala</translation> @@ -3635,6 +3709,10 @@ Cüzdan yedeÄŸi geri yüklenemiyor.</translation> <translation type="unfinished">BaÅŸlatma sırasında cüzdanı yeniden tarama iÅŸlemi baÅŸarısız oldu</translation> </message> <message> + <source>Failed to start indexes, shutting down..</source> + <translation type="unfinished">Endekslerin baÅŸlatılması baÅŸarısız oldu, kapatılıyor..</translation> + </message> + <message> <source>Failed to verify database</source> <translation type="unfinished">Veritabanı doÄŸrulanamadı</translation> </message> diff --git a/src/qt/locale/bitcoin_zh-Hans.ts b/src/qt/locale/bitcoin_zh-Hans.ts index 4b2769a0c5..ce422f6337 100644 --- a/src/qt/locale/bitcoin_zh-Hans.ts +++ b/src/qt/locale/bitcoin_zh-Hans.ts @@ -611,7 +611,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </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> @@ -1308,7 +1308,7 @@ The migration process will create a backup of the wallet before migrating. This </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>&Address</source> diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts index 0b2297d0b7..2db719f7c8 100644 --- a/src/qt/locale/bitcoin_zh.ts +++ b/src/qt/locale/bitcoin_zh.ts @@ -434,10 +434,6 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">%1 å—节</translation> </message> <message> - <source>%1 MB</source> - <translation type="unfinished">%1 MB (百è¬ä½å…ƒçµ„)</translation> - </message> - <message> <source>%1 GB</source> <translation type="unfinished">%1 GB (åå„„ä½å…ƒçµ„)</translation> </message> diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index 7bc6ccdc49..7580f6b47a 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -25,6 +25,7 @@ ModalOverlay::ModalOverlay(bool enable_wallet, QWidget* parent) parent->installEventFilter(this); raise(); } + ui->closeButton->installEventFilter(this); blockProcessTime.clear(); setVisible(false); @@ -60,6 +61,11 @@ bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) { raise(); } } + + if (obj == ui->closeButton && ev->type() == QEvent::FocusOut && layerIsVisible) { + ui->closeButton->setFocus(Qt::OtherFocusReason); + } + return QWidget::eventFilter(obj, ev); } @@ -187,6 +193,10 @@ void ModalOverlay::showHide(bool hide, bool userRequested) m_animation.setEndValue(QPoint(0, hide ? height() : 0)); m_animation.start(QAbstractAnimation::KeepWhenStopped); layerIsVisible = !hide; + + if (layerIsVisible) { + ui->closeButton->setFocus(Qt::OtherFocusReason); + } } void ModalOverlay::closeClicked() diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index b6314f5533..d3f7c02d05 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -19,6 +19,7 @@ static const struct { } network_styles[] = { {ChainType::MAIN, QAPP_APP_NAME_DEFAULT, 0, 0}, {ChainType::TESTNET, QAPP_APP_NAME_TESTNET, 70, 30}, + {ChainType::TESTNET4, QAPP_APP_NAME_TESTNET4, 70, 30}, {ChainType::SIGNET, QAPP_APP_NAME_SIGNET, 35, 15}, {ChainType::REGTEST, QAPP_APP_NAME_REGTEST, 160, 30}, }; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ee53a59bb5..4db2d6016c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -87,11 +87,13 @@ void setupFontOptions(QComboBox* cb, QLabel* preview) } OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) - : QDialog(parent, GUIUtil::dialog_flags), + : QDialog(parent, GUIUtil::dialog_flags | Qt::WindowMaximizeButtonHint), ui(new Ui::OptionsDialog) { ui->setupUi(this); + ui->verticalLayout->setStretchFactor(ui->tabWidget, 1); + /* Main elements init */ ui->databaseCache->setMinimum(nMinDbCache); ui->databaseCache->setMaximum(nMaxDbCache); @@ -440,7 +442,7 @@ void OptionsDialog::updateProxyValidationState() QValidatedLineEdit *otherProxyWidget = (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor; if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0)) { - setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid + setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxies are valid clearStatusLabel(); } else diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index edf417a7cb..ae3f9aa686 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -560,6 +560,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty ui->lineEdit->setMaxLength(16 * 1024 * 1024); ui->messagesWidget->installEventFilter(this); + connect(ui->hidePeersDetailButton, &QAbstractButton::clicked, this, &RPCConsole::clearSelectedNode); connect(ui->clearButton, &QAbstractButton::clicked, [this] { clear(); }); connect(ui->fontBiggerButton, &QAbstractButton::clicked, this, &RPCConsole::fontBigger); connect(ui->fontSmallerButton, &QAbstractButton::clicked, this, &RPCConsole::fontSmaller); @@ -977,6 +978,18 @@ void RPCConsole::updateNetworkState() } ui->numberOfConnections->setText(connections); + + QString local_addresses; + std::map<CNetAddr, LocalServiceInfo> hosts = clientModel->getNetLocalAddresses(); + for (const auto& [addr, info] : hosts) { + local_addresses += QString::fromStdString(addr.ToStringAddr()); + if (!addr.IsI2P()) local_addresses += ":" + QString::number(info.nPort); + local_addresses += ", "; + } + local_addresses.chop(2); // remove last ", " + if (local_addresses.isEmpty()) local_addresses = tr("None"); + + ui->localAddresses->setText(local_addresses); } void RPCConsole::setNumConnections(int count) @@ -1000,15 +1013,16 @@ void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVer } } -void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) +void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage, size_t maxUsage) { ui->mempoolNumberTxs->setText(QString::number(numberOfTxs)); - if (dynUsage < 1000000) { - ui->mempoolSize->setText(QObject::tr("%1 kB").arg(dynUsage / 1000.0, 0, 'f', 2)); - } else { - ui->mempoolSize->setText(QObject::tr("%1 MB").arg(dynUsage / 1000000.0, 0, 'f', 2)); - } + const auto cur_usage_str = dynUsage < 1000000 ? + QObject::tr("%1 kB").arg(dynUsage / 1000.0, 0, 'f', 2) : + QObject::tr("%1 MB").arg(dynUsage / 1000000.0, 0, 'f', 2); + const auto max_usage_str = QObject::tr("%1 MB").arg(maxUsage / 1000000.0, 0, 'f', 2); + + ui->mempoolSize->setText(cur_usage_str + " / " + max_usage_str); } void RPCConsole::on_lineEdit_returnPressed() @@ -1250,6 +1264,7 @@ void RPCConsole::updateDetailWidget() ui->peerRelayTxes->setText(stats->nodeStateStats.m_relay_txs ? ts.yes : ts.no); } + ui->hidePeersDetailButton->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove"))); ui->peersTabRightPanel->show(); } @@ -1400,4 +1415,4 @@ void RPCConsole::updateWindowTitle() const QString chainType = QString::fromStdString(Params().GetChainTypeString()); const QString title = tr("Node window - [%1]").arg(chainType); this->setWindowTitle(title); -}
\ No newline at end of file +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index d6a5035c33..4747e611d0 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -121,7 +121,7 @@ public Q_SLOTS: /** Set number of blocks and last block date shown in the UI */ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype); /** Set size (number of transactions and memory usage) of the mempool in the UI */ - void setMempoolSize(long numberOfTxs, size_t dynUsage); + void setMempoolSize(long numberOfTxs, size_t dynUsage, size_t maxUsage); /** Go forward or back in history */ void browseHistory(int offset); /** Scroll console view to end */ diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index f310d0a02b..c150606cfb 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -28,7 +28,7 @@ #include <functional> -#if defined(QT_STATICPLUGIN) +#if defined(QT_STATIC) #include <QtPlugin> #if defined(QT_QPA_PLATFORM_MINIMAL) Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h index e64f2cace1..b92df67f41 100644 --- a/src/qt/transactiondesc.h +++ b/src/qt/transactiondesc.h @@ -29,7 +29,7 @@ public: static QString toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord* rec, BitcoinUnit unit); private: - TransactionDesc() {} + TransactionDesc() = default; static QString FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool); }; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index d4267fcf61..9214e7723d 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -277,7 +277,7 @@ void TransactionTableModel::updateAmountColumnTitle() void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction) { uint256 updated; - updated.SetHex(hash.toStdString()); + updated.SetHexDeprecated(hash.toStdString()); priv->updateWallet(walletModel->wallet(), updated, status, showTransaction); } diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 7e24dbd3ec..2aaa65c6f7 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -396,7 +396,7 @@ void TransactionView::contextualMenu(const QPoint &point) // check if transaction can be abandoned, disable context menu action in case it doesn't uint256 hash; - hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString()); + hash.SetHexDeprecated(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString()); abandonAction->setEnabled(model->wallet().transactionCanBeAbandoned(hash)); bumpFeeAction->setEnabled(model->wallet().transactionCanBeBumped(hash)); copyAddressAction->setEnabled(GUIUtil::hasEntryData(transactionView, 0, TransactionTableModel::AddressRole)); @@ -416,7 +416,7 @@ void TransactionView::abandonTx() // get the hash from the TxHashRole (QVariant / QString) uint256 hash; QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString(); - hash.SetHex(hashQStr.toStdString()); + hash.SetHexDeprecated(hashQStr.toStdString()); // Abandon the wallet transaction over the walletModel model->wallet().abandonTransaction(hash); @@ -431,7 +431,7 @@ void TransactionView::bumpFee([[maybe_unused]] bool checked) // get the hash from the TxHashRole (QVariant / QString) uint256 hash; QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString(); - hash.SetHex(hashQStr.toStdString()); + hash.SetHexDeprecated(hashQStr.toStdString()); // Bump tx fee over the walletModel uint256 newHash; diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 34b47c90a3..512ea8a1dc 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -65,16 +65,16 @@ WalletController::~WalletController() delete m_activity_worker; } -std::map<std::string, bool> WalletController::listWalletDir() const +std::map<std::string, std::pair<bool, std::string>> WalletController::listWalletDir() const { QMutexLocker locker(&m_mutex); - std::map<std::string, bool> wallets; - for (const std::string& name : m_node.walletLoader().listWalletDir()) { - wallets[name] = false; + std::map<std::string, std::pair<bool, std::string>> wallets; + for (const auto& [name, format] : m_node.walletLoader().listWalletDir()) { + wallets[name] = std::make_pair(false, format); } for (WalletModel* wallet_model : m_wallets) { auto it = wallets.find(wallet_model->wallet().getWalletName()); - if (it != wallets.end()) it->second = true; + if (it != wallets.end()) it->second.first = true; } return wallets; } @@ -150,9 +150,10 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal assert(called); connect(wallet_model, &WalletModel::unload, this, [this, wallet_model] { - // Defer removeAndDeleteWallet when no modal widget is active. + // Defer removeAndDeleteWallet when no modal widget is actively waiting for an action. // TODO: remove this workaround by removing usage of QDialog::exec. - if (QApplication::activeModalWidget()) { + QWidget* active_dialog = QApplication::activeModalWidget(); + if (active_dialog && dynamic_cast<QProgressDialog*>(active_dialog) == nullptr) { connect(qApp, &QApplication::focusWindowChanged, wallet_model, [this, wallet_model]() { if (!QApplication::activeModalWidget()) { removeAndDeleteWallet(wallet_model); @@ -343,7 +344,7 @@ void OpenWalletActivity::finish() void OpenWalletActivity::open(const std::string& path) { - QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + QString name = GUIUtil::WalletDisplayName(path); showProgressDialog( //: Title of window indicating the progress of opening of a wallet. @@ -436,12 +437,12 @@ void RestoreWalletActivity::finish() Q_EMIT finished(); } -void MigrateWalletActivity::migrate(WalletModel* wallet_model) +void MigrateWalletActivity::migrate(const std::string& name) { // Warn the user about migration QMessageBox box(m_parent_widget); box.setWindowTitle(tr("Migrate wallet")); - box.setText(tr("Are you sure you wish to migrate the wallet <i>%1</i>?").arg(GUIUtil::HtmlEscape(wallet_model->getDisplayName()))); + box.setText(tr("Are you sure you wish to migrate the wallet <i>%1</i>?").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(name)))); box.setInformativeText(tr("Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made.\n" "If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts.\n" "If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts.\n\n" @@ -452,31 +453,25 @@ void MigrateWalletActivity::migrate(WalletModel* wallet_model) box.setDefaultButton(QMessageBox::Yes); if (box.exec() != QMessageBox::Yes) return; - // Get the passphrase if it is encrypted regardless of it is locked or unlocked. We need the passphrase itself. SecureString passphrase; - WalletModel::EncryptionStatus enc_status = wallet_model->getEncryptionStatus(); - if (enc_status == WalletModel::EncryptionStatus::Locked || enc_status == WalletModel::EncryptionStatus::Unlocked) { - AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, m_parent_widget, &passphrase); - dlg.setModel(wallet_model); - dlg.exec(); + if (node().walletLoader().isEncrypted(name)) { + // Get the passphrase for the wallet + AskPassphraseDialog dlg(AskPassphraseDialog::UnlockMigration, m_parent_widget, &passphrase); + if (dlg.exec() == QDialog::Rejected) return; } - // GUI needs to remove the wallet so that it can actually be unloaded by migration - const std::string name = wallet_model->wallet().getWalletName(); - m_wallet_controller->removeAndDeleteWallet(wallet_model); - showProgressDialog(tr("Migrate Wallet"), tr("Migrating Wallet <b>%1</b>…").arg(GUIUtil::HtmlEscape(name))); QTimer::singleShot(0, worker(), [this, name, passphrase] { auto res{node().walletLoader().migrateWallet(name, passphrase)}; if (res) { - m_success_message = tr("The wallet '%1' was migrated successfully.").arg(GUIUtil::HtmlEscape(res->wallet->getWalletName())); + m_success_message = tr("The wallet '%1' was migrated successfully.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->wallet->getWalletName()))); if (res->watchonly_wallet_name) { - m_success_message += QChar(' ') + tr("Watchonly scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(res->watchonly_wallet_name.value())); + m_success_message += QChar(' ') + tr("Watchonly scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->watchonly_wallet_name.value()))); } if (res->solvables_wallet_name) { - m_success_message += QChar(' ') + tr("Solvable but not watched scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(res->solvables_wallet_name.value())); + m_success_message += QChar(' ') + tr("Solvable but not watched scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->solvables_wallet_name.value()))); } m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(res->wallet)); } else { diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index c595ba998d..7902c3b235 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -61,13 +61,11 @@ public: //! Returns all wallet names in the wallet dir mapped to whether the wallet //! is loaded. - std::map<std::string, bool> listWalletDir() const; + std::map<std::string, std::pair<bool, std::string>> listWalletDir() const; void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); void closeAllWallets(QWidget* parent = nullptr); - void migrateWallet(WalletModel* wallet_model, QWidget* parent = nullptr); - Q_SIGNALS: void walletAdded(WalletModel* wallet_model); void walletRemoved(WalletModel* wallet_model); @@ -186,7 +184,7 @@ class MigrateWalletActivity : public WalletControllerActivity public: MigrateWalletActivity(WalletController* wallet_controller, QWidget* parent) : WalletControllerActivity(wallet_controller, parent) {} - void migrate(WalletModel* wallet_model); + void migrate(const std::string& path); Q_SIGNALS: void migrated(WalletModel* wallet_model); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index f8ce068e12..0a01c0a45b 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -594,8 +594,7 @@ QString WalletModel::getWalletName() const QString WalletModel::getDisplayName() const { - const QString name = getWalletName(); - return name.isEmpty() ? "["+tr("default wallet")+"]" : name; + return GUIUtil::WalletDisplayName(getWalletName()); } bool WalletModel::isMultiwallet() const diff --git a/src/random.cpp b/src/random.cpp index 239d5bc6fe..7cb6098d54 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -23,6 +23,7 @@ #include <array> #include <cmath> #include <cstdlib> +#include <optional> #include <thread> #ifdef WIN32 @@ -44,13 +45,23 @@ #include <sys/auxv.h> #endif -[[noreturn]] static void RandFailure() +namespace { + +/* Number of random bytes returned by GetOSRand. + * When changing this constant make sure to change all call sites, and make + * sure that the underlying OS APIs for all platforms support the number. + * (many cap out at 256 bytes). + */ +static const int NUM_OS_RANDOM_BYTES = 32; + + +[[noreturn]] void RandFailure() { - LogPrintf("Failed to read randomness, aborting\n"); + LogError("Failed to read randomness, aborting\n"); std::abort(); } -static inline int64_t GetPerformanceCounter() noexcept +inline int64_t GetPerformanceCounter() noexcept { // Read the hardware time stamp counter when available. // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information. @@ -71,10 +82,10 @@ static inline int64_t GetPerformanceCounter() noexcept } #ifdef HAVE_GETCPUID -static bool g_rdrand_supported = false; -static bool g_rdseed_supported = false; -static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; -static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000; +bool g_rdrand_supported = false; +bool g_rdseed_supported = false; +constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; +constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000; #ifdef bit_RDRND static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND"); #endif @@ -82,7 +93,7 @@ static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND" static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED, "Unexpected value for bit_RDSEED"); #endif -static void InitHardwareRand() +void InitHardwareRand() { uint32_t eax, ebx, ecx, edx; GetCPUID(1, 0, eax, ebx, ecx, edx); @@ -95,7 +106,7 @@ static void InitHardwareRand() } } -static void ReportHardwareRand() +void ReportHardwareRand() { // This must be done in a separate function, as InitHardwareRand() may be indirectly called // from global constructors, before logging is initialized. @@ -111,7 +122,7 @@ static void ReportHardwareRand() * * Must only be called when RdRand is supported. */ -static uint64_t GetRdRand() noexcept +uint64_t GetRdRand() noexcept { // RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk. #ifdef __i386__ @@ -146,7 +157,7 @@ static uint64_t GetRdRand() noexcept * * Must only be called when RdSeed is supported. */ -static uint64_t GetRdSeed() noexcept +uint64_t GetRdSeed() noexcept { // RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered, // but pause after every failure. @@ -180,16 +191,16 @@ static uint64_t GetRdSeed() noexcept #elif defined(__aarch64__) && defined(HWCAP2_RNG) -static bool g_rndr_supported = false; +bool g_rndr_supported = false; -static void InitHardwareRand() +void InitHardwareRand() { if (getauxval(AT_HWCAP2) & HWCAP2_RNG) { g_rndr_supported = true; } } -static void ReportHardwareRand() +void ReportHardwareRand() { // This must be done in a separate function, as InitHardwareRand() may be indirectly called // from global constructors, before logging is initialized. @@ -202,7 +213,7 @@ static void ReportHardwareRand() * * Must only be called when RNDR is supported. */ -static uint64_t GetRNDR() noexcept +uint64_t GetRNDR() noexcept { uint8_t ok; uint64_t r1; @@ -220,7 +231,7 @@ static uint64_t GetRNDR() noexcept * * Must only be called when RNDRRS is supported. */ -static uint64_t GetRNDRRS() noexcept +uint64_t GetRNDRRS() noexcept { uint8_t ok; uint64_t r1; @@ -240,12 +251,12 @@ static uint64_t GetRNDRRS() noexcept * Slower sources should probably be invoked separately, and/or only from * RandAddPeriodic (which is called once a minute). */ -static void InitHardwareRand() {} -static void ReportHardwareRand() {} +void InitHardwareRand() {} +void ReportHardwareRand() {} #endif /** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */ -static void SeedHardwareFast(CSHA512& hasher) noexcept { +void SeedHardwareFast(CSHA512& hasher) noexcept { #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) if (g_rdrand_supported) { uint64_t out = GetRdRand(); @@ -262,7 +273,7 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept { } /** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */ -static void SeedHardwareSlow(CSHA512& hasher) noexcept { +void SeedHardwareSlow(CSHA512& hasher) noexcept { #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) // When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's // guaranteed to produce independent randomness on every call. @@ -295,7 +306,7 @@ 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], SteadyClock::duration dur, CSHA512& hasher) noexcept +void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept { CSHA512 inner_hasher; inner_hasher.Write(seed, sizeof(seed)); @@ -326,7 +337,7 @@ static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration du /** Fallback: get 32 bytes of system entropy from /dev/urandom. The most * compatible way to get cryptographic randomness on UNIX-ish platforms. */ -[[maybe_unused]] static void GetDevURandom(unsigned char *ent32) +[[maybe_unused]] void GetDevURandom(unsigned char *ent32) { int f = open("/dev/urandom", O_RDONLY); if (f == -1) { @@ -401,8 +412,6 @@ void GetOSRand(unsigned char *ent32) #endif } -namespace { - class RNGState { Mutex m_mutex; /* The RNG state consists of 256 bits of entropy, taken from the output of @@ -417,6 +426,10 @@ class RNGState { uint64_t m_counter GUARDED_BY(m_mutex) = 0; bool m_strongly_seeded GUARDED_BY(m_mutex) = false; + /** If not nullopt, the output of this RNGState is redirected and drawn from here + * (unless always_use_real_rng is passed to MixExtract). */ + std::optional<ChaCha20> m_deterministic_prng GUARDED_BY(m_mutex); + Mutex m_events_mutex; CSHA256 m_events_hasher GUARDED_BY(m_events_mutex); @@ -457,11 +470,21 @@ public: m_events_hasher.Write(events_hash, 32); } + /** Make the output of MixExtract (unless always_use_real_rng) deterministic, with specified seed. */ + void MakeDeterministic(const uint256& seed) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + LOCK(m_mutex); + m_deterministic_prng.emplace(MakeByteSpan(seed)); + } + /** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher. * * If this function has never been called with strong_seed = true, false is returned. + * + * If always_use_real_rng is false, and MakeDeterministic has been called before, output + * from the deterministic PRNG instead. */ - bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed, bool always_use_real_rng) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { assert(num <= 32); unsigned char buf[64]; @@ -479,6 +502,13 @@ public: hasher.Finalize(buf); // Store the last 32 bytes of the hash output as new RNG state. memcpy(m_state, buf + 32, 32); + // Handle requests for deterministic randomness. + if (!always_use_real_rng && m_deterministic_prng.has_value()) [[unlikely]] { + // Overwrite the beginning of buf, which will be used for output. + m_deterministic_prng->Keystream(AsWritableBytes(Span{buf, num})); + // Do not require strong seeding for deterministic output. + ret = true; + } } // If desired, copy (up to) the first 32 bytes of the hash output as output. if (num) { @@ -499,20 +529,19 @@ RNGState& GetRNGState() noexcept static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1); return g_rng[0]; } -} /* A note on the use of noexcept in the seeding functions below: * * None of the RNG code should ever throw any exception. */ -static void SeedTimestamp(CSHA512& hasher) noexcept +void SeedTimestamp(CSHA512& hasher) noexcept { int64_t perfcounter = GetPerformanceCounter(); hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter)); } -static void SeedFast(CSHA512& hasher) noexcept +void SeedFast(CSHA512& hasher) noexcept { unsigned char buffer[32]; @@ -527,7 +556,7 @@ static void SeedFast(CSHA512& hasher) noexcept SeedTimestamp(hasher); } -static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept +void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept { unsigned char buffer[32]; @@ -549,16 +578,17 @@ 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, SteadyClock::duration dur) noexcept +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. + // Never use the deterministic PRNG for this, as the result is only used internally. unsigned char strengthen_seed[32]; - rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false); + rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false, /*always_use_real_rng=*/true); // Strengthen the seed, and feed it into hasher. Strengthen(strengthen_seed, dur, hasher); } -static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept +void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept { // Everything that the 'fast' seeder includes SeedFast(hasher); @@ -578,7 +608,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept SeedStrengthen(hasher, rng, 10ms); } -static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept +void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept { // Gather 256 bits of hardware randomness, if available SeedHardwareSlow(hasher); @@ -604,7 +634,7 @@ enum class RNGLevel { PERIODIC, //!< Called by RandAddPeriodic() }; -static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept +void ProcRand(unsigned char* out, int num, RNGLevel level, bool always_use_real_rng) noexcept { // Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available). RNGState& rng = GetRNGState(); @@ -625,65 +655,61 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept } // Combine with and update state - if (!rng.MixExtract(out, num, std::move(hasher), false)) { + if (!rng.MixExtract(out, num, std::move(hasher), false, always_use_real_rng)) { // On the first invocation, also seed with SeedStartup(). CSHA512 startup_hasher; SeedStartup(startup_hasher, rng); - rng.MixExtract(out, num, std::move(startup_hasher), true); + rng.MixExtract(out, num, std::move(startup_hasher), true, always_use_real_rng); } } -void GetRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST); } -void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW); } -void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); } -void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); } +} // namespace -bool g_mock_deterministic_tests{false}; -uint64_t GetRandInternal(uint64_t nMax) noexcept +/** Internal function to set g_determinstic_rng. Only accessed from tests. */ +void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept { - return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); + GetRNGState().MakeDeterministic(seed); } -uint256 GetRandHash() noexcept +void GetRandBytes(Span<unsigned char> bytes) noexcept { - uint256 hash; - GetRandBytes(hash); - return hash; + ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST, /*always_use_real_rng=*/false); } -void FastRandomContext::RandomSeed() +void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { - uint256 seed = GetRandHash(); - rng.SetKey(MakeByteSpan(seed)); - requires_seed = false; + ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW, /*always_use_real_rng=*/true); } -uint256 FastRandomContext::rand256() noexcept +void RandAddPeriodic() noexcept { - if (requires_seed) RandomSeed(); - uint256 ret; - rng.Keystream(MakeWritableByteSpan(ret)); - return ret; + ProcRand(nullptr, 0, RNGLevel::PERIODIC, /*always_use_real_rng=*/false); } -template <typename B> -std::vector<B> FastRandomContext::randbytes(size_t len) +void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); } + +void FastRandomContext::RandomSeed() noexcept { - std::vector<B> ret(len); - fillrand(MakeWritableByteSpan(ret)); - return ret; + uint256 seed = GetRandHash(); + rng.SetKey(MakeByteSpan(seed)); + requires_seed = false; } -template std::vector<unsigned char> FastRandomContext::randbytes(size_t); -template std::vector<std::byte> FastRandomContext::randbytes(size_t); -void FastRandomContext::fillrand(Span<std::byte> output) +void FastRandomContext::fillrand(Span<std::byte> output) noexcept { if (requires_seed) RandomSeed(); rng.Keystream(output); } -FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), rng(MakeByteSpan(seed)), bitbuf_size(0) {} +FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), rng(MakeByteSpan(seed)) {} + +void FastRandomContext::Reseed(const uint256& seed) noexcept +{ + FlushCache(); + requires_seed = false; + rng = {MakeByteSpan(seed)}; +} bool Random_SanityCheck() { @@ -726,41 +752,38 @@ bool Random_SanityCheck() CSHA512 to_add; to_add.Write((const unsigned char*)&start, sizeof(start)); to_add.Write((const unsigned char*)&stop, sizeof(stop)); - GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false); + GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false, /*always_use_real_rng=*/true); return true; } static constexpr std::array<std::byte, ChaCha20::KEYLEN> ZERO_KEY{}; -FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), rng(ZERO_KEY), bitbuf_size(0) +FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), rng(ZERO_KEY) { // Note that despite always initializing with ZERO_KEY, requires_seed is set to true if not // fDeterministic. That means the rng will be reinitialized with a secure random key upon first // use. } -FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept -{ - requires_seed = from.requires_seed; - rng = from.rng; - bitbuf = from.bitbuf; - bitbuf_size = from.bitbuf_size; - from.requires_seed = true; - from.bitbuf_size = 0; - return *this; -} - void RandomInit() { // Invoke RNG code to trigger initialization (if not already performed) - ProcRand(nullptr, 0, RNGLevel::FAST); + ProcRand(nullptr, 0, RNGLevel::FAST, /*always_use_real_rng=*/true); ReportHardwareRand(); } -std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval) +double MakeExponentiallyDistributed(uint64_t uniform) noexcept { - double unscaled = -std::log1p(GetRand(uint64_t{1} << 48) * -0.0000000000000035527136788 /* -1/2^48 */); - return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us); + // To convert uniform into an exponentially-distributed double, we use two steps: + // - Convert uniform into a uniformly-distributed double in range [0, 1), use the expression + // ((uniform >> 11) * 0x1.0p-53), as described in https://prng.di.unimi.it/ under + // "Generating uniform doubles in the unit interval". Call this value x. + // - Given an x in uniformly distributed in [0, 1), we find an exponentially distributed value + // by applying the quantile function to it. For the exponential distribution with mean 1 this + // is F(x) = -log(1 - x). + // + // Combining the two, and using log1p(x) = log(1 + x), we obtain the following: + return -std::log1p((uniform >> 11) * -0x1.0p-53); } diff --git a/src/random.h b/src/random.h index f7c20ee4b0..536e697cca 100644 --- a/src/random.h +++ b/src/random.h @@ -10,12 +10,15 @@ #include <crypto/common.h> #include <span.h> #include <uint256.h> +#include <util/check.h> #include <bit> #include <cassert> #include <chrono> +#include <concepts> #include <cstdint> #include <limits> +#include <type_traits> #include <vector> /** @@ -25,8 +28,8 @@ * The following (classes of) functions interact with that state by mixing in new * entropy, and optionally extracting random output from it: * - * - The GetRand*() class of functions, as well as construction of FastRandomContext objects, - * perform 'fast' seeding, consisting of mixing in: + * - GetRandBytes, GetRandHash, GetRandDur, as well as construction of FastRandomContext + * objects, perform 'fast' seeding, consisting of mixing in: * - A stack pointer (indirectly committing to calling thread and call stack) * - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise) * - 64 bits from the hardware RNG (rdrand) when available. @@ -35,7 +38,7 @@ * FastRandomContext on the other hand does not protect against this once created, but * is even faster (and acceptable to use inside tight loops). * - * - The GetStrongRand*() class of function perform 'slow' seeding, including everything + * - The GetStrongRandBytes() function performs 'slow' seeding, including everything * that fast seeding includes, but additionally: * - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if * this entropy source fails. @@ -50,253 +53,416 @@ * - Strengthen the entropy for 10 ms using repeated SHA512. * This is run once every minute. * - * On first use of the RNG (regardless of what function is called first), all entropy - * sources used in the 'slow' seeder are included, but also: - * - 256 bits from the hardware RNG (rdseed or rdrand) when available. - * - Dynamic environment data (performance monitoring, ...) - * - Static environment data - * - Strengthen the entropy for 100 ms using repeated SHA512. + * - On first use of the RNG (regardless of what function is called first), all entropy + * sources used in the 'slow' seeder are included, but also: + * - 256 bits from the hardware RNG (rdseed or rdrand) when available. + * - Dynamic environment data (performance monitoring, ...) + * - Static environment data + * - Strengthen the entropy for 100 ms using repeated SHA512. * * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes * become the new RNG state. + * + * During tests, the RNG can be put into a special deterministic mode, in which the output + * of all RNG functions, with the exception of GetStrongRandBytes(), is replaced with the + * output of a deterministic RNG. This deterministic RNG does not gather entropy, and is + * unaffected by RandAddPeriodic() or RandAddEvent(). It produces pseudorandom data that + * only depends on the seed it was initialized with, possibly until it is reinitialized. */ + +/* ============================= INITIALIZATION AND ADDING ENTROPY ============================= */ + /** - * Generate random data via the internal PRNG. + * Initialize global RNG state and log any CPU features that are used. * - * These functions are designed to be fast (sub microsecond), but do not necessarily - * meaningfully add entropy to the PRNG state. + * Calling this function is optional. RNG state will be initialized when first + * needed if it is not called. + */ +void RandomInit(); + +/** + * Gather entropy from various expensive sources, and feed them to the PRNG state. * * Thread-safe. */ -void GetRandBytes(Span<unsigned char> bytes) noexcept; -/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */ -uint64_t GetRandInternal(uint64_t nMax) noexcept; -/** Generate a uniform random integer of type T in the range [0..nMax) - * nMax defaults to std::numeric_limits<T>::max() - * Precondition: nMax > 0, T is an integral type, no larger than uint64_t - */ -template<typename T> -T GetRand(T nMax=std::numeric_limits<T>::max()) noexcept { - static_assert(std::is_integral<T>(), "T must be integral"); - static_assert(std::numeric_limits<T>::max() <= std::numeric_limits<uint64_t>::max(), "GetRand only supports up to uint64_t"); - return T(GetRandInternal(nMax)); -} -/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */ -template <typename D> -D GetRandomDuration(typename std::common_type<D>::type max) noexcept -// Having the compiler infer the template argument from the function argument -// is dangerous, because the desired return value generally has a different -// type than the function argument. So std::common_type is used to force the -// call site to specify the type of the return value. -{ - assert(max.count() > 0); - return D{GetRand(max.count())}; -}; -constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>; -constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>; +void RandAddPeriodic() noexcept; /** - * Return a timestamp in the future sampled from an exponential distribution - * (https://en.wikipedia.org/wiki/Exponential_distribution). This distribution - * is memoryless and should be used for repeated network events (e.g. sending a - * certain type of message) to minimize leaking information to observers. + * Gathers entropy from the low bits of the time at which events occur. Should + * be called with a uint32_t describing the event at the time an event occurs. * - * The probability of an event occurring before time x is 1 - e^-(x/a) where a - * is the average interval between events. - * */ -std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval); + * Thread-safe. + */ +void RandAddEvent(const uint32_t event_info) noexcept; -uint256 GetRandHash() noexcept; + +/* =========================== BASE RANDOMNESS GENERATION FUNCTIONS =========================== + * + * All produced randomness is eventually generated by one of these functions. + */ /** - * Gather entropy from various sources, feed it into the internal PRNG, and - * generate random data using it. + * Generate random data via the internal PRNG. * - * This function will cause failure whenever the OS RNG fails. + * These functions are designed to be fast (sub microsecond), but do not necessarily + * meaningfully add entropy to the PRNG state. + * + * In test mode (see SeedRandomForTest in src/test/util/random.h), the normal PRNG state is + * bypassed, and a deterministic, seeded, PRNG is used instead. * * Thread-safe. */ -void GetStrongRandBytes(Span<unsigned char> bytes) noexcept; +void GetRandBytes(Span<unsigned char> bytes) noexcept; /** - * Gather entropy from various expensive sources, and feed them to the PRNG state. + * Gather entropy from various sources, feed it into the internal PRNG, and + * generate random data using it. + * + * This function will cause failure whenever the OS RNG fails. + * + * The normal PRNG is never bypassed here, even in test mode. * * Thread-safe. */ -void RandAddPeriodic() noexcept; +void GetStrongRandBytes(Span<unsigned char> bytes) noexcept; -/** - * Gathers entropy from the low bits of the time at which events occur. Should - * be called with a uint32_t describing the event at the time an event occurs. + +/* ============================= RANDOM NUMBER GENERATION CLASSES ============================= * - * Thread-safe. + * In this section, 3 classes are defined: + * - RandomMixin: a base class that adds functionality to all RNG classes. + * - FastRandomContext: a cryptographic RNG (seeded through GetRandBytes in its default + * constructor). + * - InsecureRandomContext: a non-cryptographic, very fast, RNG. */ -void RandAddEvent(const uint32_t event_info) noexcept; -/** - * Fast randomness source. This is seeded once with secure random data, but - * is completely deterministic and does not gather more entropy after that. +// Forward declaration of RandomMixin, used in RandomNumberGenerator concept. +template<typename T> +class RandomMixin; + +/** A concept for RandomMixin-based random number generators. */ +template<typename T> +concept RandomNumberGenerator = requires(T& rng, Span<std::byte> s) { + // A random number generator must provide rand64(). + { rng.rand64() } noexcept -> std::same_as<uint64_t>; + // A random number generator must derive from RandomMixin, which adds other rand* functions. + requires std::derived_from<std::remove_reference_t<T>, RandomMixin<std::remove_reference_t<T>>>; +}; + +/** A concept for C++ std::chrono durations. */ +template<typename T> +concept StdChronoDuration = requires { + []<class Rep, class Period>(std::type_identity<std::chrono::duration<Rep, Period>>){}( + std::type_identity<T>()); +}; + +/** Given a uniformly random uint64_t, return an exponentially distributed double with mean 1. */ +double MakeExponentiallyDistributed(uint64_t uniform) noexcept; + +/** Mixin class that provides helper randomness functions. * - * This class is not thread-safe. + * Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp. + * An RNG class FunkyRNG would derive publicly from RandomMixin<FunkyRNG>. This permits + * RandomMixin from accessing the derived class's rand64() function, while also allowing + * the derived class to provide more. + * + * The derived class must satisfy the RandomNumberGenerator concept. */ -class FastRandomContext +template<typename T> +class RandomMixin { private: - bool requires_seed; - ChaCha20 rng; - - uint64_t bitbuf; - int bitbuf_size; + uint64_t bitbuf{0}; + int bitbuf_size{0}; - void RandomSeed(); + /** Access the underlying generator. + * + * This also enforces the RandomNumberGenerator concept. We cannot declare that in the template + * (no template<RandomNumberGenerator T>) because the type isn't fully instantiated yet there. + */ + RandomNumberGenerator auto& Impl() noexcept { return static_cast<T&>(*this); } - void FillBitBuffer() +protected: + constexpr void FlushCache() noexcept { - bitbuf = rand64(); - bitbuf_size = 64; + bitbuf = 0; + bitbuf_size = 0; } public: - explicit FastRandomContext(bool fDeterministic = false) noexcept; - - /** Initialize with explicit seed (only for testing) */ - explicit FastRandomContext(const uint256& seed) noexcept; + constexpr RandomMixin() noexcept = default; - // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded). - FastRandomContext(const FastRandomContext&) = delete; - FastRandomContext(FastRandomContext&&) = delete; - FastRandomContext& operator=(const FastRandomContext&) = delete; - - /** Move a FastRandomContext. If the original one is used again, it will be reseeded. */ - FastRandomContext& operator=(FastRandomContext&& from) noexcept; - - /** Generate a random 64-bit integer. */ - uint64_t rand64() noexcept - { - if (requires_seed) RandomSeed(); - std::array<std::byte, 8> buf; - rng.Keystream(buf); - return ReadLE64(UCharCast(buf.data())); - } + // Do not permit copying or moving an RNG. + RandomMixin(const RandomMixin&) = delete; + RandomMixin& operator=(const RandomMixin&) = delete; + RandomMixin(RandomMixin&&) = delete; + RandomMixin& operator=(RandomMixin&&) = delete; /** Generate a random (bits)-bit integer. */ uint64_t randbits(int bits) noexcept { - if (bits == 0) { - return 0; - } else if (bits > 32) { - return rand64() >> (64 - bits); - } else { - if (bitbuf_size < bits) FillBitBuffer(); - uint64_t ret = bitbuf & (~uint64_t{0} >> (64 - bits)); + Assume(bits <= 64); + // Requests for the full 64 bits are passed through. + if (bits == 64) return Impl().rand64(); + uint64_t ret; + if (bits <= bitbuf_size) { + // If there is enough entropy left in bitbuf, return its bottom bits bits. + ret = bitbuf; bitbuf >>= bits; bitbuf_size -= bits; - return ret; + } else { + // If not, return all of bitbuf, supplemented with the (bits - bitbuf_size) bottom + // bits of a newly generated 64-bit number on top. The remainder of that generated + // number becomes the new bitbuf. + uint64_t gen = Impl().rand64(); + ret = (gen << bitbuf_size) | bitbuf; + bitbuf = gen >> (bits - bitbuf_size); + bitbuf_size = 64 + bitbuf_size - bits; } + // Return the bottom bits bits of ret. + return ret & ((uint64_t{1} << bits) - 1); } - /** Generate a random integer in the range [0..range). - * Precondition: range > 0. - */ - uint64_t randrange(uint64_t range) noexcept + /** Same as above, but with compile-time fixed bits count. */ + template<int Bits> + uint64_t randbits() noexcept { - assert(range); - --range; - int bits = std::bit_width(range); + static_assert(Bits >= 0 && Bits <= 64); + if constexpr (Bits == 64) { + return Impl().rand64(); + } else { + uint64_t ret; + if (Bits <= bitbuf_size) { + ret = bitbuf; + bitbuf >>= Bits; + bitbuf_size -= Bits; + } else { + uint64_t gen = Impl().rand64(); + ret = (gen << bitbuf_size) | bitbuf; + bitbuf = gen >> (Bits - bitbuf_size); + bitbuf_size = 64 + bitbuf_size - Bits; + } + constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1; + return ret & MASK; + } + } + + /** Generate a random integer in the range [0..range), with range > 0. */ + template<std::integral I> + I randrange(I range) noexcept + { + static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max()); + Assume(range > 0); + uint64_t maxval = range - 1U; + int bits = std::bit_width(maxval); while (true) { - uint64_t ret = randbits(bits); - if (ret <= range) return ret; + uint64_t ret = Impl().randbits(bits); + if (ret <= maxval) return ret; } } - /** Generate random bytes. */ - template <typename B = unsigned char> - std::vector<B> randbytes(size_t len); + /** Fill a Span with random bytes. */ + void fillrand(Span<std::byte> span) noexcept + { + while (span.size() >= 8) { + uint64_t gen = Impl().rand64(); + WriteLE64(UCharCast(span.data()), gen); + span = span.subspan(8); + } + if (span.size() >= 4) { + uint32_t gen = Impl().rand32(); + WriteLE32(UCharCast(span.data()), gen); + span = span.subspan(4); + } + while (span.size()) { + span[0] = std::byte(Impl().template randbits<8>()); + span = span.subspan(1); + } + } - /** Fill a byte Span with random bytes. */ - void fillrand(Span<std::byte> output); + /** Generate a random integer in its entire (non-negative) range. */ + template<std::integral I> + I rand() noexcept + { + static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max()); + static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max())); + static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS)); + return I(Impl().template randbits<BITS>()); + } + + /** Generate random bytes. */ + template <BasicByte B = unsigned char> + std::vector<B> randbytes(size_t len) noexcept + { + std::vector<B> ret(len); + Impl().fillrand(MakeWritableByteSpan(ret)); + return ret; + } /** Generate a random 32-bit integer. */ - uint32_t rand32() noexcept { return randbits(32); } + uint32_t rand32() noexcept { return Impl().template randbits<32>(); } /** generate a random uint256. */ - uint256 rand256() noexcept; + uint256 rand256() noexcept + { + uint256 ret; + Impl().fillrand(MakeWritableByteSpan(ret)); + return ret; + } /** Generate a random boolean. */ - bool randbool() noexcept { return randbits(1); } + bool randbool() noexcept { return Impl().template randbits<1>(); } /** Return the time point advanced by a uniform random duration. */ template <typename Tp> - Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) + Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) noexcept { - return time + rand_uniform_duration<Tp>(range); + return time + Impl().template rand_uniform_duration<Tp>(range); } /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */ - template <typename Chrono> + template <typename Chrono> requires StdChronoDuration<typename Chrono::duration> typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept { using Dur = typename Chrono::duration; - return range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} : - range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} : + return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} : + range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} : /* interval [0..0] */ Dur{0}; }; + /** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */ + template <StdChronoDuration Dur> + Dur randrange(typename std::common_type_t<Dur> range) noexcept + // Having the compiler infer the template argument from the function argument + // is dangerous, because the desired return value generally has a different + // type than the function argument. So std::common_type is used to force the + // call site to specify the type of the return value. + { + return Dur{Impl().randrange(range.count())}; + } + + /** + * Return a duration sampled from an exponential distribution + * (https://en.wikipedia.org/wiki/Exponential_distribution). Successive events + * whose intervals are distributed according to this form a memoryless Poisson + * process. This should be used for repeated network events (e.g. sending a + * certain type of message) to minimize leaking information to observers. + * + * The probability of an event occurring before time x is 1 - e^-(x/a) where a + * is the average interval between events. + * */ + std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept + { + using namespace std::chrono_literals; + auto unscaled = MakeExponentiallyDistributed(Impl().rand64()); + return std::chrono::duration_cast<std::chrono::microseconds>(unscaled * mean + 0.5us); + } + // 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(); } - inline uint64_t operator()() noexcept { return rand64(); } + static constexpr uint64_t min() noexcept { return 0; } + static constexpr uint64_t max() noexcept { return std::numeric_limits<uint64_t>::max(); } + inline uint64_t operator()() noexcept { return Impl().rand64(); } }; -/** More efficient than using std::shuffle on a FastRandomContext. - * - * This is more efficient as std::shuffle will consume entropy in groups of - * 64 bits at the time and throw away most. +/** + * Fast randomness source. This is seeded once with secure random data, but + * is completely deterministic and does not gather more entropy after that. * - * This also works around a bug in libstdc++ std::shuffle that may cause - * type::operator=(type&&) to be invoked on itself, which the library's - * debug mode detects and panics on. This is a known issue, see - * https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle + * This class is not thread-safe. */ -template <typename I, typename R> -void Shuffle(I first, I last, R&& rng) +class FastRandomContext : public RandomMixin<FastRandomContext> { - while (first != last) { - size_t j = rng.randrange(last - first); - if (j) { - using std::swap; - swap(*first, *(first + j)); - } - ++first; +private: + bool requires_seed; + ChaCha20 rng; + + void RandomSeed() noexcept; + +public: + /** Construct a FastRandomContext with GetRandHash()-based entropy (or zero key if fDeterministic). */ + explicit FastRandomContext(bool fDeterministic = false) noexcept; + + /** Initialize with explicit seed (only for testing) */ + explicit FastRandomContext(const uint256& seed) noexcept; + + /** Reseed with explicit seed (only for testing). */ + void Reseed(const uint256& seed) noexcept; + + /** Generate a random 64-bit integer. */ + uint64_t rand64() noexcept + { + if (requires_seed) RandomSeed(); + std::array<std::byte, 8> buf; + rng.Keystream(buf); + return ReadLE64(UCharCast(buf.data())); } -} -/* Number of random bytes returned by GetOSRand. - * When changing this constant make sure to change all call sites, and make - * sure that the underlying OS APIs for all platforms support the number. - * (many cap out at 256 bytes). - */ -static const int NUM_OS_RANDOM_BYTES = 32; + /** Fill a byte Span with random bytes. This overrides the RandomMixin version. */ + void fillrand(Span<std::byte> output) noexcept; +}; -/** Get 32 bytes of system entropy. Do not use this in application code: use - * GetStrongRandBytes instead. +/** xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes. + * + * Memory footprint is very small, 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/ */ -void GetOSRand(unsigned char* ent32); +class InsecureRandomContext : public RandomMixin<InsecureRandomContext> +{ + uint64_t m_s0; + uint64_t m_s1; + + [[nodiscard]] constexpr static uint64_t SplitMix64(uint64_t& seedval) noexcept + { + uint64_t z = (seedval += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); + } + +public: + constexpr explicit InsecureRandomContext(uint64_t seedval) noexcept + : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval)) {} + + constexpr void Reseed(uint64_t seedval) noexcept + { + FlushCache(); + m_s0 = SplitMix64(seedval); + m_s1 = SplitMix64(seedval); + } + + constexpr uint64_t rand64() noexcept + { + uint64_t s0 = m_s0, s1 = m_s1; + const uint64_t result = std::rotl(s0 + s1, 17) + s0; + s1 ^= s0; + m_s0 = std::rotl(s0, 49) ^ s1 ^ (s1 << 21); + m_s1 = std::rotl(s1, 28); + return result; + } +}; + + +/* ==================== CONVENIENCE FUNCTIONS FOR COMMONLY USED RANDOMNESS ==================== */ + +/** Generate a random uint256. */ +inline uint256 GetRandHash() noexcept +{ + uint256 hash; + GetRandBytes(hash); + return hash; +} + +/* ============================= MISCELLANEOUS TEST-ONLY FUNCTIONS ============================= */ /** Check that OS randomness is available and returning the requested number * of bytes. */ bool Random_SanityCheck(); -/** - * Initialize global RNG state and log any CPU features that are used. - * - * Calling this function is optional. RNG state will be initialized when first - * needed if it is not called. - */ -void RandomInit(); - #endif // BITCOIN_RANDOM_H diff --git a/src/randomenv.cpp b/src/randomenv.cpp index 49033deef2..4754b597c5 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -58,7 +58,9 @@ #include <sys/auxv.h> #endif +#ifndef _MSC_VER extern char** environ; // NOLINT(readability-redundant-declaration): Necessary on some platforms +#endif namespace { @@ -69,10 +71,10 @@ void RandAddSeedPerfmon(CSHA512& hasher) // This can take up to 2 seconds, so only do it every 10 minutes. // Initialize last_perfmon to 0 seconds, we don't skip the first call. - static std::atomic<std::chrono::seconds> last_perfmon{0s}; + static std::atomic<SteadyClock::time_point> last_perfmon{SteadyClock::time_point{0s}}; auto last_time = last_perfmon.load(); - auto current_time = GetTime<std::chrono::seconds>(); - if (current_time < last_time + std::chrono::minutes{10}) return; + auto current_time = SteadyClock::now(); + if (current_time < last_time + 10min) return; last_perfmon = current_time; std::vector<unsigned char> vData(250000, 0); diff --git a/src/rest.cpp b/src/rest.cpp index 4abbc4d2ca..c42bc8e40c 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -217,9 +217,10 @@ static bool rest_headers(const std::any& context, return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, raw_count)); } - uint256 hash; - if (!ParseHashStr(hashStr, hash)) + auto hash{uint256::FromHex(hashStr)}; + if (!hash) { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); + } const CBlockIndex* tip = nullptr; std::vector<const CBlockIndex*> headers; @@ -231,7 +232,7 @@ static bool rest_headers(const std::any& context, LOCK(cs_main); CChain& active_chain = chainman.ActiveChain(); tip = active_chain.Tip(); - const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash); + const CBlockIndex* pindex{chainman.m_blockman.LookupBlockIndex(*hash)}; while (pindex != nullptr && active_chain.Contains(pindex)) { headers.push_back(pindex); if (headers.size() == *parsed_count) { @@ -290,9 +291,10 @@ static bool rest_block(const std::any& context, std::string hashStr; const RESTResponseFormat rf = ParseDataFormat(hashStr, strURIPart); - uint256 hash; - if (!ParseHashStr(hashStr, hash)) + auto hash{uint256::FromHex(hashStr)}; + if (!hash) { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); + } FlatFilePos pos{}; const CBlockIndex* pblockindex = nullptr; @@ -303,7 +305,7 @@ static bool rest_block(const std::any& context, { LOCK(cs_main); tip = chainman.ActiveChain().Tip(); - pblockindex = chainman.m_blockman.LookupBlockIndex(hash); + pblockindex = chainman.m_blockman.LookupBlockIndex(*hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -390,8 +392,8 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, raw_count)); } - uint256 block_hash; - if (!ParseHashStr(raw_blockhash, block_hash)) { + auto block_hash{uint256::FromHex(raw_blockhash)}; + if (!block_hash) { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + raw_blockhash); } @@ -413,7 +415,7 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); CChain& active_chain = chainman.ActiveChain(); - const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block_hash); + const CBlockIndex* pindex{chainman.m_blockman.LookupBlockIndex(*block_hash)}; while (pindex != nullptr && active_chain.Contains(pindex)) { headers.push_back(pindex); if (headers.size() == *parsed_count) @@ -494,8 +496,8 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>"); } - uint256 block_hash; - if (!ParseHashStr(uri_parts[1], block_hash)) { + auto block_hash{uint256::FromHex(uri_parts[1])}; + if (!block_hash) { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + uri_parts[1]); } @@ -516,7 +518,7 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s if (!maybe_chainman) return false; ChainstateManager& chainman = *maybe_chainman; LOCK(cs_main); - block_index = chainman.m_blockman.LookupBlockIndex(block_hash); + block_index = chainman.m_blockman.LookupBlockIndex(*block_hash); if (!block_index) { return RESTERR(req, HTTP_NOT_FOUND, uri_parts[1] + " not found"); } @@ -616,14 +618,14 @@ static bool rest_deploymentinfo(const std::any& context, HTTPRequest* req, const jsonRequest.params = UniValue(UniValue::VARR); if (!hash_str.empty()) { - uint256 hash; - if (!ParseHashStr(hash_str, hash)) { + auto hash{uint256::FromHex(hash_str)}; + if (!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")))) { + if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(*hash))) { return RESTERR(req, HTTP_BAD_REQUEST, "Block not found"); } @@ -704,9 +706,10 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string std::string hashStr; const RESTResponseFormat rf = ParseDataFormat(hashStr, strURIPart); - uint256 hash; - if (!ParseHashStr(hashStr, hash)) + auto hash{uint256::FromHex(hashStr)}; + if (!hash) { return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); + } if (g_txindex) { g_txindex->BlockUntilSyncedToCurrentChain(); @@ -715,7 +718,7 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string const NodeContext* const node = GetNodeContext(context, req); if (!node) return false; uint256 hashBlock = uint256(); - const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, node->mempool.get(), hash, hashBlock, node->chainman->m_blockman); + const CTransactionRef tx{GetTransaction(/*block_index=*/nullptr, node->mempool.get(), *hash, hashBlock, node->chainman->m_blockman)}; if (!tx) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -788,14 +791,18 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++) { - int32_t nOutput; - std::string strTxid = uriParts[i].substr(0, uriParts[i].find('-')); - std::string strOutput = uriParts[i].substr(uriParts[i].find('-')+1); + const auto txid_out{util::Split<std::string_view>(uriParts[i], '-')}; + if (txid_out.size() != 2) { + return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); + } + auto txid{Txid::FromHex(txid_out.at(0))}; + auto output{ToIntegral<uint32_t>(txid_out.at(1))}; - if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid)) + if (!txid || !output) { return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); + } - vOutPoints.emplace_back(TxidFromString(strTxid), (uint32_t)nOutput); + vOutPoints.emplace_back(*txid, *output); } if (vOutPoints.size() > 0) diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h deleted file mode 100644 index 4db001c04b..0000000000 --- a/src/reverse_iterator.h +++ /dev/null @@ -1,39 +0,0 @@ -// Taken from https://gist.github.com/arvidsson/7231973 - -#ifndef BITCOIN_REVERSE_ITERATOR_H -#define BITCOIN_REVERSE_ITERATOR_H - -/** - * 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)) - * std::cout << x << " "; - */ - -template <typename T> -class reverse_range -{ - T &m_x; - -public: - explicit reverse_range(T &x) : m_x(x) {} - - auto begin() const -> decltype(this->m_x.rbegin()) - { - return m_x.rbegin(); - } - - auto end() const -> decltype(this->m_x.rend()) - { - return m_x.rend(); - } -}; - -template <typename T> -reverse_range<T> reverse_iterate(T &x) -{ - return reverse_range<T>(x); -} - -#endif // BITCOIN_REVERSE_ITERATOR_H diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9b5c3ab5ff..b449444aff 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -8,6 +8,7 @@ #include <blockfilter.h> #include <chain.h> #include <chainparams.h> +#include <chainparamsbase.h> #include <clientversion.h> #include <coins.h> #include <common/args.h> @@ -431,6 +432,7 @@ 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" + "The block will not have any undo data which can limit the usage of the block data in a context where the undo data is needed.\n" "Subsequent calls for the same block may 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" @@ -654,9 +656,9 @@ const RPCResult getblock_vin{ {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output 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_HEX, "hex", "The raw output 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() + ")"}, }}, @@ -784,6 +786,32 @@ static RPCHelpMan getblock() }; } +//! Return height of highest block that has been pruned, or std::nullopt if no blocks have been pruned +std::optional<int> GetPruneHeight(const BlockManager& blockman, const CChain& chain) { + AssertLockHeld(::cs_main); + + // Search for the last block missing block data or undo data. Don't let the + // search consider the genesis block, because the genesis block does not + // have undo data, but should not be considered pruned. + const CBlockIndex* first_block{chain[1]}; + const CBlockIndex* chain_tip{chain.Tip()}; + + // If there are no blocks after the genesis block, or no blocks at all, nothing is pruned. + if (!first_block || !chain_tip) return std::nullopt; + + // If the chain tip is pruned, everything is pruned. + if (!((chain_tip->nStatus & BLOCK_HAVE_MASK) == BLOCK_HAVE_MASK)) return chain_tip->nHeight; + + const auto& first_unpruned{*CHECK_NONFATAL(blockman.GetFirstBlock(*chain_tip, /*status_mask=*/BLOCK_HAVE_MASK, first_block))}; + if (&first_unpruned == first_block) { + // All blocks between first_block and chain_tip have data, so nothing is pruned. + return std::nullopt; + } + + // Block before the first unpruned block is the last pruned block. + return CHECK_NONFATAL(first_unpruned.pprev)->nHeight; +} + static RPCHelpMan pruneblockchain() { return RPCHelpMan{"pruneblockchain", "", @@ -836,8 +864,7 @@ static RPCHelpMan pruneblockchain() } PruneBlockFilesManual(active_chainstate, height); - const CBlockIndex& block{*CHECK_NONFATAL(active_chain.Tip())}; - return block.nStatus & BLOCK_HAVE_DATA ? active_chainstate.m_blockman.GetFirstStoredBlock(block)->nHeight - 1 : block.nHeight; + return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1); }, }; } @@ -1056,9 +1083,9 @@ static RPCHelpMan gettxout() {RPCResult::Type::NUM, "confirmations", "The number of confirmations"}, {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output 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_HEX, "hex", "The raw output 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)"}, }}, @@ -1247,7 +1274,7 @@ RPCHelpMan getblockchaininfo() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"}, + {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"}, {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"}, {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"}, {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"}, @@ -1297,8 +1324,8 @@ RPCHelpMan getblockchaininfo() obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); obj.pushKV("pruned", chainman.m_blockman.IsPruneMode()); if (chainman.m_blockman.IsPruneMode()) { - bool has_tip_data = tip.nStatus & BLOCK_HAVE_DATA; - obj.pushKV("pruneheight", has_tip_data ? chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight : tip.nHeight + 1); + const auto prune_height{GetPruneHeight(chainman.m_blockman, active_chainstate.m_chain)}; + obj.pushKV("pruneheight", prune_height ? prune_height.value() + 1 : 0); const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL}; obj.pushKV("automatic_pruning", automatic_pruning); @@ -1696,24 +1723,22 @@ static RPCHelpMan getchaintxstats() const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))}; const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()}; - const auto window_tx_count{ - (pindex->nChainTx != 0 && past_block.nChainTx != 0) ? std::optional{pindex->nChainTx - past_block.nChainTx} : std::nullopt, - }; UniValue ret(UniValue::VOBJ); ret.pushKV("time", (int64_t)pindex->nTime); - if (pindex->nChainTx) { - ret.pushKV("txcount", pindex->nChainTx); + if (pindex->m_chain_tx_count) { + ret.pushKV("txcount", pindex->m_chain_tx_count); } ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex()); ret.pushKV("window_final_block_height", pindex->nHeight); ret.pushKV("window_block_count", blockcount); if (blockcount > 0) { ret.pushKV("window_interval", nTimeDiff); - if (window_tx_count) { - ret.pushKV("window_tx_count", *window_tx_count); + if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) { + const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count; + ret.pushKV("window_tx_count", window_tx_count); if (nTimeDiff > 0) { - ret.pushKV("txrate", double(*window_tx_count) / nTimeDiff); + ret.pushKV("txrate", double(window_tx_count) / nTimeDiff); } } } @@ -2136,14 +2161,14 @@ static const auto scan_result_status_some = RPCResult{ static RPCHelpMan scantxoutset() { - // scriptPubKey corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S + // raw() descriptor corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy"; return RPCHelpMan{"scantxoutset", "\nScans the unspent transaction output set for entries that match certain output descriptors.\n" "Examples of output descriptors are:\n" - " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n" - " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" + " addr(<address>) Outputs whose output script corresponds to the specified address (does not include P2PK)\n" + " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\n" " 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" @@ -2164,7 +2189,7 @@ static RPCHelpMan scantxoutset() RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", { {RPCResult::Type::BOOL, "success", "Whether the scan was completed"}, {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"}, - {RPCResult::Type::NUM, "height", "The current block height (index)"}, + {RPCResult::Type::NUM, "height", "The block height at which the scan was done"}, {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"}, {RPCResult::Type::ARR, "unspents", "", { @@ -2172,11 +2197,13 @@ static RPCHelpMan scantxoutset() { {RPCResult::Type::STR_HEX, "txid", "The transaction id"}, {RPCResult::Type::NUM, "vout", "The vout value"}, - {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"}, - {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"}, + {RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"}, + {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"}, {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_HEX, "blockhash", "Blockhash of the unspent transaction output"}, + {RPCResult::Type::NUM, "confirmations", "Number of confirmations of the unspent transaction output when the scan was done"}, }}, }}, {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT}, @@ -2266,17 +2293,20 @@ static RPCHelpMan scantxoutset() const COutPoint& outpoint = it.first; const Coin& coin = it.second; const CTxOut& txo = coin.out; + const CBlockIndex& coinb_block{*CHECK_NONFATAL(tip->GetAncestor(coin.nHeight))}; input_txos.push_back(txo); total_in += txo.nValue; UniValue unspent(UniValue::VOBJ); unspent.pushKV("txid", outpoint.hash.GetHex()); - unspent.pushKV("vout", (int32_t)outpoint.n); + unspent.pushKV("vout", outpoint.n); 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); + unspent.pushKV("height", coin.nHeight); + unspent.pushKV("blockhash", coinb_block.GetBlockHash().GetHex()); + unspent.pushKV("confirmations", tip->nHeight - coin.nHeight + 1); unspents.push_back(std::move(unspent)); } @@ -2712,7 +2742,7 @@ UniValue CreateUTXOSnapshot( tip->nHeight, tip->GetBlockHash().ToString(), fs::PathToString(path), fs::PathToString(temppath))); - SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), tip->nHeight, maybe_stats->coins_count}; + SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), maybe_stats->coins_count}; afile << metadata; @@ -2770,7 +2800,7 @@ UniValue CreateUTXOSnapshot( result.pushKV("base_height", tip->nHeight); result.pushKV("path", path.utf8string()); result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString()); - result.pushKV("nchaintx", tip->nChainTx); + result.pushKV("nchaintx", tip->m_chain_tx_count); return result; } @@ -2814,7 +2844,7 @@ static RPCHelpMan loadtxoutset() { NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); - fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(request.params[0].get_str()))}; + const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string>("path")))}; FILE* file{fsbridge::fopen(path, "rb")}; AutoFile afile{file}; @@ -2833,13 +2863,15 @@ static RPCHelpMan loadtxoutset() auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)}; if (!activation_result) { - throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf(_("Unable to load UTXO snapshot: %s\n"), util::ErrorString(activation_result)).original); + throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string())); } + CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)}; + UniValue result(UniValue::VOBJ); result.pushKV("coins_loaded", metadata.m_coins_count); - result.pushKV("tip_hash", metadata.m_base_blockhash.ToString()); - result.pushKV("base_height", metadata.m_base_blockheight); + result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString()); + result.pushKV("base_height", snapshot_index.nHeight); result.pushKV("path", fs::PathToString(path)); return result; }, diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index c2021c3608..f6a7fe236c 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -21,6 +21,7 @@ class CBlockIndex; class Chainstate; class UniValue; namespace node { +class BlockManager; struct NodeContext; } // namespace node @@ -57,4 +58,7 @@ UniValue CreateUTXOSnapshot( const fs::path& path, const fs::path& tmppath); +//! Return height of highest block that has been pruned, or std::nullopt if no blocks have been pruned +std::optional<int> GetPruneHeight(const node::BlockManager& blockman, const CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + #endif // BITCOIN_RPC_BLOCKCHAIN_H diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 7dfe69a6c5..b866fa484b 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -146,6 +146,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "fundrawtransaction", 1, "conf_target"}, { "fundrawtransaction", 1, "replaceable"}, { "fundrawtransaction", 1, "solving_data"}, + { "fundrawtransaction", 1, "max_tx_weight"}, { "fundrawtransaction", 2, "iswitness" }, { "walletcreatefundedpsbt", 0, "inputs" }, { "walletcreatefundedpsbt", 1, "outputs" }, @@ -164,6 +165,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "walletcreatefundedpsbt", 3, "conf_target"}, { "walletcreatefundedpsbt", 3, "replaceable"}, { "walletcreatefundedpsbt", 3, "solving_data"}, + { "walletcreatefundedpsbt", 3, "max_tx_weight"}, { "walletcreatefundedpsbt", 4, "bip32derivs" }, { "walletprocesspsbt", 1, "sign" }, { "walletprocesspsbt", 3, "bip32derivs" }, @@ -208,6 +210,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "send", 4, "conf_target"}, { "send", 4, "replaceable"}, { "send", 4, "solving_data"}, + { "send", 4, "max_tx_weight"}, { "sendall", 0, "recipients" }, { "sendall", 1, "conf_target" }, { "sendall", 3, "fee_rate"}, diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index aefe78162b..10caa9ed2e 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -23,7 +23,7 @@ #include <string> using common::FeeModeFromString; -using common::FeeModes; +using common::FeeModesDetail; using common::InvalidEstimateModeErrorMessage; using node::NodeContext; @@ -36,13 +36,8 @@ static RPCHelpMan estimatesmartfee() "in BIP 141 (witness data is discounted).\n", { {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, - {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"conservative"}, "The fee estimate mode.\n" - "Whether to return a more conservative estimate which also satisfies\n" - "a longer history. A conservative estimate potentially returns a\n" - "higher feerate and is more likely to be sufficient for the desired\n" - "target, but is not as responsive to short term drops in the\n" - "prevailing fee market. Must be one of (case insensitive):\n" - "\"" + FeeModes("\"\n\"") + "\""}, + {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n" + + FeeModesDetail(std::string("default mode will be used"))}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -71,13 +66,13 @@ static RPCHelpMan estimatesmartfee() CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue(); unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); - bool conservative = true; + bool conservative = false; if (!request.params[1].isNull()) { FeeEstimateMode fee_mode; if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) { throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); } - if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false; + if (fee_mode == FeeEstimateMode::CONSERVATIVE) conservative = true; } UniValue result(UniValue::VOBJ); diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index b67d272b65..d61898260b 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -43,7 +43,7 @@ static RPCHelpMan sendrawtransaction() "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n" "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n" "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n" - "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_CHAIN, may throw if the transaction cannot be added to the mempool.\n" + "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n" "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 7e420dcd9b..3c41e136ec 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -7,6 +7,7 @@ #include <chain.h> #include <chainparams.h> +#include <chainparamsbase.h> #include <common/system.h> #include <consensus/amount.h> #include <consensus/consensus.h> @@ -345,13 +346,11 @@ static RPCHelpMan generateblock() std::vector<CTransactionRef> txs; const auto raw_txs_or_txids = request.params[1].get_array(); for (size_t i = 0; i < raw_txs_or_txids.size(); i++) { - const auto str(raw_txs_or_txids[i].get_str()); + const auto& str{raw_txs_or_txids[i].get_str()}; - uint256 hash; CMutableTransaction mtx; - if (ParseHashStr(str, hash)) { - - const auto tx = mempool.get(hash); + if (auto hash{uint256::FromHex(str)}) { + const auto tx{mempool.get(*hash)}; if (!tx) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str)); } @@ -371,7 +370,7 @@ static RPCHelpMan generateblock() ChainstateManager& chainman = EnsureChainman(node); { - std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)}; + std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, {.use_mempool = false})}; if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); } @@ -424,7 +423,7 @@ static RPCHelpMan getmininginfo() {RPCResult::Type::NUM, "difficulty", "The current difficulty"}, {RPCResult::Type::NUM, "networkhashps", "The network hashes per second"}, {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"}, - {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"}, + {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"}, (IsDeprecatedRPCEnabled("warnings") ? RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} : RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)", @@ -778,9 +777,7 @@ static RPCHelpMan getblocktemplate() } ENTER_CRITICAL_SECTION(cs_main); - std::optional<uint256> maybe_tip{miner.getTipHash()}; - CHECK_NONFATAL(maybe_tip); - tip = maybe_tip.value(); + tip = CHECK_NONFATAL(miner.getTipHash()).value(); if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 65b0a93cdd..54e2c8e226 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -221,7 +221,6 @@ static RPCHelpMan logging() "The valid logging categories are: " + LogInstance().LogCategoriesString() + "\n" "In addition, the following are available as category names with special meanings:\n" " - \"all\", \"1\" : represent all logging categories.\n" - " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n" , { {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to add to debug logging", diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index 65a9be2762..01a9e59284 100644 --- a/src/rpc/output_script.cpp +++ b/src/rpc/output_script.cpp @@ -38,7 +38,7 @@ static RPCHelpMan validateaddress() { {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address validated"}, - {RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded scriptPubKey generated by the address"}, + {RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded output script generated by the address"}, {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"}, {RPCResult::Type::BOOL, "iswitness", /*optional=*/true, "If the address is a witness address"}, {RPCResult::Type::NUM, "witness_version", /*optional=*/true, "The version number of the witness program"}, @@ -217,7 +217,7 @@ static RPCHelpMan deriveaddresses() " 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" + " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\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" diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 83a9010681..0574335c96 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -46,14 +46,13 @@ enum RPCErrorCode RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules - RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain + RPC_VERIFY_ALREADY_IN_UTXO_SET = -27, //!< Transaction already in utxo set RPC_IN_WARMUP = -28, //!< Client still warming up RPC_METHOD_DEPRECATED = -32, //!< RPC method is deprecated //! Aliases for backward compatibility RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR, RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED, - RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN, //! P2P client errors RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 75b538061d..21bc0e52f1 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -85,9 +85,9 @@ 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, "asm", "Disassembly of the output 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_HEX, "hex", "The raw output 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() + ")"}, }; @@ -506,18 +506,18 @@ static RPCHelpMan decodescript() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR, "asm", "Script public key"}, + {RPCResult::Type::STR, "asm", "Disassembly of the script"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "p2sh", /*optional=*/true, "address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"}, {RPCResult::Type::OBJ, "segwit", /*optional=*/true, - "Result of a witness script public key wrapping this redeem script (not returned for types that should not be wrapped)", + "Result of a witness output script wrapping this redeem script (not returned for types that should not be wrapped)", { - {RPCResult::Type::STR, "asm", "String representation of the script public key"}, - {RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"}, - {RPCResult::Type::STR, "type", "The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, + {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, + {RPCResult::Type::STR, "type", "The type of the output script (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "p2sh-segwit", "address of the P2SH script wrapping this witness redeem script"}, @@ -557,6 +557,7 @@ static RPCHelpMan decodescript() case TxoutType::SCRIPTHASH: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: + case TxoutType::ANCHOR: // Should not be wrapped return false; } // no default case, so the compiler can warn about missing cases @@ -599,6 +600,7 @@ static RPCHelpMan decodescript() case TxoutType::WITNESS_V0_KEYHASH: case TxoutType::WITNESS_V0_SCRIPTHASH: case TxoutType::WITNESS_V1_TAPROOT: + case TxoutType::ANCHOR: // Should not be wrapped return false; } // no default case, so the compiler can warn about missing cases @@ -735,7 +737,7 @@ static RPCHelpMan signrawtransactionwithkey() { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"}, + {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "output script"}, {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"}, {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"}, {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"}, @@ -833,9 +835,9 @@ const RPCResult decodepsbt_inputs{ {RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { - {RPCResult::Type::STR, "asm", "Disassembly of the public key script"}, + {RPCResult::Type::STR, "asm", "Disassembly of the output 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_HEX, "hex", "The raw output 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)"}, }}, @@ -1790,8 +1792,8 @@ static RPCHelpMan joinpsbts() std::iota(output_indices.begin(), output_indices.end(), 0); // Shuffle input and output indices lists - Shuffle(input_indices.begin(), input_indices.end(), FastRandomContext()); - Shuffle(output_indices.begin(), output_indices.end(), FastRandomContext()); + std::shuffle(input_indices.begin(), input_indices.end(), FastRandomContext()); + std::shuffle(output_indices.begin(), output_indices.end(), FastRandomContext()); PartiallySignedTransaction shuffled_psbt; shuffled_psbt.tx = CMutableTransaction(); @@ -1838,8 +1840,8 @@ static RPCHelpMan analyzepsbt() { {RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose signature is missing"}, }}, - {RPCResult::Type::STR_HEX, "redeemscript", /*optional=*/true, "Hash160 of the redeemScript that is missing"}, - {RPCResult::Type::STR_HEX, "witnessscript", /*optional=*/true, "SHA256 of the witnessScript that is missing"}, + {RPCResult::Type::STR_HEX, "redeemscript", /*optional=*/true, "Hash160 of the redeem script that is missing"}, + {RPCResult::Type::STR_HEX, "witnessscript", /*optional=*/true, "SHA256 of the witness script that is missing"}, }}, {RPCResult::Type::STR, "next", /*optional=*/true, "Role of the next person that this input needs to go to"}, }}, diff --git a/src/rpc/server.h b/src/rpc/server.h index 5735aff821..56e8a63088 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -48,7 +48,7 @@ bool RPCIsInWarmup(std::string *outStatus); class RPCTimerBase { public: - virtual ~RPCTimerBase() {} + virtual ~RPCTimerBase() = default; }; /** @@ -57,7 +57,7 @@ public: class RPCTimerInterface { public: - virtual ~RPCTimerInterface() {} + virtual ~RPCTimerInterface() = default; /** Implementation name */ virtual const char *Name() = 0; /** Factory function for timers. diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 4df4466c49..cc49670198 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -332,6 +332,14 @@ public: return obj; } + UniValue operator()(const PayToAnchor& anchor) const + { + UniValue obj(UniValue::VOBJ); + obj.pushKV("isscript", true); + obj.pushKV("iswitness", true); + return obj; + } + UniValue operator()(const WitnessUnknown& id) const { UniValue obj(UniValue::VOBJ); @@ -391,8 +399,8 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr) switch (terr) { case TransactionError::MEMPOOL_REJECTED: return RPC_TRANSACTION_REJECTED; - case TransactionError::ALREADY_IN_CHAIN: - return RPC_TRANSACTION_ALREADY_IN_CHAIN; + case TransactionError::ALREADY_IN_UTXO_SET: + return RPC_VERIFY_ALREADY_IN_UTXO_SET; default: break; } return RPC_TRANSACTION_ERROR; diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 0987db194c..ae9dba6a50 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -116,13 +116,13 @@ std::string DescriptorChecksum(const Span<const char>& span) * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect * the position within the groups. */ - static std::string INPUT_CHARSET = + static const std::string INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}" "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~" "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; /** The character set for the checksum itself (same as bech32). */ - static std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + static const std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; uint64_t c = 1; int cls = 0; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 20a9830d0e..9d0e9b5e3c 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1943,6 +1943,8 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, } return set_success(serror); } + } else if (!is_p2sh && CScript::IsPayToAnchor(witversion, program)) { + return true; } else { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 836c2e7982..8ba0018c23 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -265,7 +265,7 @@ public: return false; } - virtual ~BaseSignatureChecker() {} + virtual ~BaseSignatureChecker() = default; }; /** Enum to specify what *TransactionSignatureChecker's behavior should be diff --git a/src/script/miniscript.h b/src/script/miniscript.h index a269709e72..58f24434f0 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -305,7 +305,7 @@ struct InputStack { //! Data elements. std::vector<std::vector<unsigned char>> stack; //! Construct an empty stack (valid). - InputStack() {} + InputStack() = default; //! 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 @@ -1793,8 +1793,9 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) // Get threshold int next_comma = FindNextChar(in, ','); if (next_comma < 1) return false; - int64_t k; - if (!ParseInt64(std::string(in.begin(), in.begin() + next_comma), &k)) return false; + const auto k_to_integral{ToIntegral<int64_t>(std::string_view(in.begin(), next_comma))}; + if (!k_to_integral.has_value()) return false; + const int64_t k{k_to_integral.value()}; in = in.subspan(next_comma + 1); // Get keys. It is compatible for both compressed and x-only keys. std::vector<Key> keys; @@ -1948,21 +1949,19 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) } else if (Const("after(", in)) { int arg_size = FindNextChar(in, ')'); if (arg_size < 1) return {}; - int64_t num; - if (!ParseInt64(std::string(in.begin(), in.begin() + arg_size), &num)) return {}; - if (num < 1 || num >= 0x80000000L) return {}; - constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, num)); + const auto num{ToIntegral<int64_t>(std::string_view(in.begin(), arg_size))}; + if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {}; + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::AFTER, *num)); in = in.subspan(arg_size + 1); - script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff); + script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff); } else if (Const("older(", in)) { int arg_size = FindNextChar(in, ')'); if (arg_size < 1) return {}; - int64_t num; - if (!ParseInt64(std::string(in.begin(), in.begin() + arg_size), &num)) return {}; - if (num < 1 || num >= 0x80000000L) return {}; - constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, num)); + const auto num{ToIntegral<int64_t>(std::string_view(in.begin(), arg_size))}; + if (!num.has_value() || *num < 1 || *num >= 0x80000000L) return {}; + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, ctx.MsContext(), Fragment::OLDER, *num)); in = in.subspan(arg_size + 1); - script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff); + script_size += 1 + (*num > 16) + (*num > 0x7f) + (*num > 0x7fff) + (*num > 0x7fffff); } else if (Const("multi(", in)) { if (!parse_multi_exp(in, /* is_multi_a = */false)) return {}; } else if (Const("multi_a(", in)) { @@ -1970,13 +1969,13 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) } else if (Const("thresh(", in)) { int next_comma = FindNextChar(in, ','); if (next_comma < 1) return {}; - if (!ParseInt64(std::string(in.begin(), in.begin() + next_comma), &k)) return {}; - if (k < 1) return {}; + const auto k{ToIntegral<int64_t>(std::string_view(in.begin(), next_comma))}; + if (!k.has_value() || *k < 1) return {}; in = in.subspan(next_comma + 1); // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH - to_parse.emplace_back(ParseContext::THRESH, 1, k); + to_parse.emplace_back(ParseContext::THRESH, 1, *k); to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); - script_size += 2 + (k > 16) + (k > 0x7f) + (k > 0x7fff) + (k > 0x7fffff); + script_size += 2 + (*k > 16) + (*k > 0x7f) + (*k > 0x7fff) + (*k > 0x7fffff); } else if (Const("andor(", in)) { to_parse.emplace_back(ParseContext::ANDOR, -1, -1); to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1); diff --git a/src/script/script.cpp b/src/script/script.cpp index 73ea336c4f..d650db9a0d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -204,6 +204,23 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } +bool CScript::IsPayToAnchor() const +{ + return (this->size() == 4 && + (*this)[0] == OP_1 && + (*this)[1] == 0x02 && + (*this)[2] == 0x4e && + (*this)[3] == 0x73); +} + +bool CScript::IsPayToAnchor(int version, const std::vector<unsigned char>& program) +{ + return version == 1 && + program.size() == 2 && + program[0] == 0x4e && + program[1] == 0x73; +} + bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: diff --git a/src/script/script.h b/src/script/script.h index 66d63fae89..323411251c 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -430,7 +430,7 @@ protected: return *this; } public: - CScript() { } + CScript() = default; CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { } CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { } CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } @@ -533,6 +533,14 @@ public: */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + /* + * OP_1 <0x4e73> + */ + bool IsPayToAnchor() const; + /** Checks if output of IsWitnessProgram comes from a P2A output script + */ + static bool IsPayToAnchor(int version, const std::vector<unsigned char>& program); + bool IsPayToScriptHash() const; bool IsPayToWitnessScriptHash() const; bool IsWitnessProgram(int& version, std::vector<unsigned char>& program) const; @@ -569,7 +577,7 @@ struct CScriptWitness std::vector<std::vector<unsigned char> > stack; // Some compilers complain without a default constructor - CScriptWitness() { } + CScriptWitness() = default; bool IsNull() const { return stack.empty(); } diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 7c6c282cc4..33531e6bf5 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -5,125 +5,80 @@ #include <script/sigcache.h> -#include <common/system.h> +#include <crypto/sha256.h> #include <logging.h> #include <pubkey.h> #include <random.h> +#include <script/interpreter.h> +#include <span.h> #include <uint256.h> -#include <cuckoocache.h> - -#include <algorithm> #include <mutex> -#include <optional> #include <shared_mutex> #include <vector> -namespace { -/** - * Valid signature cache, to avoid doing expensive ECDSA signature checking - * twice for every transaction (once when accepted into memory pool, and - * again when accepted into the block chain) - */ -class CSignatureCache +SignatureCache::SignatureCache(const size_t max_size_bytes) { -private: - //! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature): - CSHA256 m_salted_hasher_ecdsa; - CSHA256 m_salted_hasher_schnorr; - typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; - map_type setValid; - std::shared_mutex cs_sigcache; - -public: - CSignatureCache() - { - uint256 nonce = GetRandHash(); - // We want the nonce to be 64 bytes long to force the hasher to process - // this chunk, which makes later hash computations more efficient. We - // just write our 32-byte entropy, and then pad with 'E' for ECDSA and - // 'S' for Schnorr (followed by 0 bytes). - static constexpr unsigned char PADDING_ECDSA[32] = {'E'}; - static constexpr unsigned char PADDING_SCHNORR[32] = {'S'}; - m_salted_hasher_ecdsa.Write(nonce.begin(), 32); - m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32); - m_salted_hasher_schnorr.Write(nonce.begin(), 32); - m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32); - } - - void - ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const - { - CSHA256 hasher = m_salted_hasher_ecdsa; - hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin()); - } - - void - ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const - { - CSHA256 hasher = m_salted_hasher_schnorr; - hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin()); - } + uint256 nonce = GetRandHash(); + // We want the nonce to be 64 bytes long to force the hasher to process + // this chunk, which makes later hash computations more efficient. We + // just write our 32-byte entropy, and then pad with 'E' for ECDSA and + // 'S' for Schnorr (followed by 0 bytes). + static constexpr unsigned char PADDING_ECDSA[32] = {'E'}; + static constexpr unsigned char PADDING_SCHNORR[32] = {'S'}; + m_salted_hasher_ecdsa.Write(nonce.begin(), 32); + m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32); + m_salted_hasher_schnorr.Write(nonce.begin(), 32); + m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32); - bool - Get(const uint256& entry, const bool erase) - { - std::shared_lock<std::shared_mutex> lock(cs_sigcache); - return setValid.contains(entry, erase); - } + const auto [num_elems, approx_size_bytes] = setValid.setup_bytes(max_size_bytes); + LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n", + approx_size_bytes >> 20, max_size_bytes >> 20, num_elems); +} - void Set(const uint256& entry) - { - std::unique_lock<std::shared_mutex> lock(cs_sigcache); - setValid.insert(entry); - } - std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n) - { - return setValid.setup_bytes(n); - } -}; +void SignatureCache::ComputeEntryECDSA(uint256& entry, const uint256& hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const +{ + CSHA256 hasher = m_salted_hasher_ecdsa; + hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin()); +} -/* In previous versions of this code, signatureCache was a local static variable - * in CachingTransactionSignatureChecker::VerifySignature. We initialize - * signatureCache outside of VerifySignature to avoid the atomic operation per - * call overhead associated with local static variables even though - * signatureCache could be made local to VerifySignature. -*/ -static CSignatureCache signatureCache; -} // namespace +void SignatureCache::ComputeEntrySchnorr(uint256& entry, const uint256& hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const +{ + CSHA256 hasher = m_salted_hasher_schnorr; + hasher.Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin()); +} -// To be called once in AppInitMain/BasicTestingSetup to initialize the -// signatureCache. -bool InitSignatureCache(size_t max_size_bytes) +bool SignatureCache::Get(const uint256& entry, const bool erase) { - auto setup_results = signatureCache.setup_bytes(max_size_bytes); - if (!setup_results) return false; + std::shared_lock<std::shared_mutex> lock(cs_sigcache); + return setValid.contains(entry, erase); +} - const auto [num_elems, approx_size_bytes] = *setup_results; - LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n", - approx_size_bytes >> 20, max_size_bytes >> 20, num_elems); - return true; +void SignatureCache::Set(const uint256& entry) +{ + std::unique_lock<std::shared_mutex> lock(cs_sigcache); + setValid.insert(entry); } bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { uint256 entry; - signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey); - if (signatureCache.Get(entry, !store)) + m_signature_cache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey); + if (m_signature_cache.Get(entry, !store)) return true; if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash)) return false; if (store) - signatureCache.Set(entry); + m_signature_cache.Set(entry); return true; } bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const { uint256 entry; - signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey); - if (signatureCache.Get(entry, !store)) return true; + m_signature_cache.ComputeEntrySchnorr(entry, sighash, sig, pubkey); + if (m_signature_cache.Get(entry, !store)) return true; if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false; - if (store) signatureCache.Set(entry); + if (store) m_signature_cache.Set(entry); return true; } diff --git a/src/script/sigcache.h b/src/script/sigcache.h index d33d60d5bc..76802e6a7c 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -6,32 +6,71 @@ #ifndef BITCOIN_SCRIPT_SIGCACHE_H #define BITCOIN_SCRIPT_SIGCACHE_H +#include <consensus/amount.h> +#include <crypto/sha256.h> +#include <cuckoocache.h> #include <script/interpreter.h> #include <span.h> +#include <uint256.h> #include <util/hasher.h> -#include <optional> +#include <cstddef> +#include <shared_mutex> #include <vector> +class CPubKey; +class CTransaction; +class XOnlyPubKey; + // DoS prevention: limit cache size to 32MiB (over 1000000 entries on 64-bit // systems). Due to how we count cache size, actual memory usage is slightly // more (~32.25 MiB) -static constexpr size_t DEFAULT_MAX_SIG_CACHE_BYTES{32 << 20}; +static constexpr size_t DEFAULT_VALIDATION_CACHE_BYTES{32 << 20}; +static constexpr size_t DEFAULT_SIGNATURE_CACHE_BYTES{DEFAULT_VALIDATION_CACHE_BYTES / 2}; +static constexpr size_t DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES{DEFAULT_VALIDATION_CACHE_BYTES / 2}; +static_assert(DEFAULT_VALIDATION_CACHE_BYTES == DEFAULT_SIGNATURE_CACHE_BYTES + DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES); -class CPubKey; +/** + * Valid signature cache, to avoid doing expensive ECDSA signature checking + * twice for every transaction (once when accepted into memory pool, and + * again when accepted into the block chain) + */ +class SignatureCache +{ +private: + //! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature): + CSHA256 m_salted_hasher_ecdsa; + CSHA256 m_salted_hasher_schnorr; + typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; + map_type setValid; + std::shared_mutex cs_sigcache; + +public: + SignatureCache(size_t max_size_bytes); + + SignatureCache(const SignatureCache&) = delete; + SignatureCache& operator=(const SignatureCache&) = delete; + + void ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const; + + void ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const; + + bool Get(const uint256& entry, const bool erase); + + void Set(const uint256& entry); +}; class CachingTransactionSignatureChecker : public TransactionSignatureChecker { private: bool store; + SignatureCache& m_signature_cache; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, SignatureCache& signature_cache, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn), m_signature_cache(signature_cache) {} bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override; bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override; }; -[[nodiscard]] bool InitSignatureCache(size_t max_size_bytes); - #endif // BITCOIN_SCRIPT_SIGCACHE_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 22ac062a63..9568348bf6 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -475,6 +475,9 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TxoutType::WITNESS_V1_TAPROOT: return SignTaproot(provider, creator, WitnessV1Taproot(XOnlyPubKey{vSolutions[0]}), sigdata, ret); + + case TxoutType::ANCHOR: + return true; } // no default case, so the compiler can warn about missing cases assert(false); } @@ -831,7 +834,7 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, } ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount, txdata, MissingDataBehavior::FAIL), &serror)) { + if (!sigdata.complete && !VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount, txdata, MissingDataBehavior::FAIL), &serror)) { if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) { // Unable to sign input and verification failed (possible attempt to partially sign). input_errors[i] = Untranslated("Unable to sign input, invalid stack size (possibly missing key)"); diff --git a/src/script/sign.h b/src/script/sign.h index ace2ba7856..4edd5bf326 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -27,7 +27,7 @@ struct CMutableTransaction; /** Interface for signature creators. */ class BaseSignatureCreator { public: - virtual ~BaseSignatureCreator() {} + virtual ~BaseSignatureCreator() = default; virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ @@ -89,7 +89,7 @@ struct SignatureData { 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() {} + SignatureData() = default; explicit SignatureData(const CScript& script) : scriptSig(script) {} void MergeSignatureData(SignatureData sigdata); }; diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index 3298376389..efdfd9ee56 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -150,7 +150,7 @@ std::optional<std::vector<std::tuple<int, std::vector<unsigned char>, int>>> Inf class SigningProvider { public: - virtual ~SigningProvider() {} + virtual ~SigningProvider() = default; virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; } virtual bool HaveCScript(const CScriptID &scriptid) const { return false; } virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; } diff --git a/src/script/solver.cpp b/src/script/solver.cpp index 3dfa9cd6ba..bd3c5cdf72 100644 --- a/src/script/solver.cpp +++ b/src/script/solver.cpp @@ -24,6 +24,7 @@ std::string GetTxnOutputType(TxoutType t) case TxoutType::SCRIPTHASH: return "scripthash"; case TxoutType::MULTISIG: return "multisig"; case TxoutType::NULL_DATA: return "nulldata"; + case TxoutType::ANCHOR: return "anchor"; case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot"; @@ -165,6 +166,9 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c vSolutionsRet.push_back(std::move(witnessprogram)); return TxoutType::WITNESS_V1_TAPROOT; } + if (scriptPubKey.IsPayToAnchor()) { + return TxoutType::ANCHOR; + } if (witnessversion != 0) { vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); diff --git a/src/script/solver.h b/src/script/solver.h index dc8f4c357d..5a7b685a6f 100644 --- a/src/script/solver.h +++ b/src/script/solver.h @@ -22,6 +22,7 @@ template <typename C> class Span; enum class TxoutType { NONSTANDARD, // 'standard' transaction types: + ANCHOR, //!< anyone can spend script PUBKEY, PUBKEYHASH, SCRIPTHASH, diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml index 4bd15511a4..0c1e01dc95 100644 --- a/src/secp256k1/.cirrus.yml +++ b/src/secp256k1/.cirrus.yml @@ -20,6 +20,7 @@ env: EXPERIMENTAL: no ECDH: no RECOVERY: no + EXTRAKEYS: no SCHNORRSIG: no ELLSWIFT: no ### test options @@ -66,6 +67,7 @@ task: env: ECDH: yes RECOVERY: yes + EXTRAKEYS: yes SCHNORRSIG: yes ELLSWIFT: yes matrix: @@ -82,6 +84,7 @@ task: env: ECDH: yes RECOVERY: yes + EXTRAKEYS: yes SCHNORRSIG: yes ELLSWIFT: yes WRAPPER_CMD: 'valgrind --error-exitcode=42' diff --git a/src/secp256k1/.github/workflows/ci.yml b/src/secp256k1/.github/workflows/ci.yml index ade94e1eec..e238f3b7a1 100644 --- a/src/secp256k1/.github/workflows/ci.yml +++ b/src/secp256k1/.github/workflows/ci.yml @@ -22,7 +22,7 @@ env: BUILD: 'check' ### secp256k1 config ECMULTWINDOW: 15 - ECMULTGENKB: 22 + ECMULTGENKB: 86 ASM: 'no' WIDEMUL: 'auto' WITH_VALGRIND: 'yes' @@ -31,6 +31,7 @@ env: EXPERIMENTAL: 'no' ECDH: 'no' RECOVERY: 'no' + EXTRAKEYS: 'no' SCHNORRSIG: 'no' ELLSWIFT: 'no' ### test options @@ -71,18 +72,18 @@ jobs: matrix: configuration: - env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' } - - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - env_vars: { WIDEMUL: 'int128' } - - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' } - - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes' } - - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } - - env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' } - - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' } + - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes' } + - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } + - env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes' } + - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' } - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } - - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 } - env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 } cc: @@ -139,6 +140,7 @@ jobs: HOST: 'i686-linux-gnu' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CC: ${{ matrix.cc }} @@ -183,6 +185,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -234,6 +237,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -279,6 +283,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -334,6 +339,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -386,6 +392,7 @@ jobs: WRAPPER_CMD: 'valgrind --error-exitcode=42' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -437,6 +444,7 @@ jobs: env: ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -501,6 +509,7 @@ jobs: env: ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CC: 'clang' @@ -547,6 +556,7 @@ jobs: WITH_VALGRIND: 'no' ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' CTIMETESTS: 'no' @@ -605,15 +615,15 @@ jobs: fail-fast: false matrix: env_vars: - - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 } - - { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } - BUILD: 'distcheck' steps: @@ -666,13 +676,13 @@ jobs: fail-fast: false matrix: env_vars: - - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } - - { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } - - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' } - BUILD: 'distcheck' steps: @@ -778,6 +788,7 @@ jobs: WERROR_CFLAGS: ECDH: 'yes' RECOVERY: 'yes' + EXTRAKEYS: 'yes' SCHNORRSIG: 'yes' ELLSWIFT: 'yes' @@ -864,5 +875,5 @@ jobs: CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install run: | - cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} --target install && ls -RlAh ${{ env.CI_INSTALL }} + cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} && cmake --install ${{ env.CI_BUILD }} && ls -RlAh ${{ env.CI_INSTALL }} gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore index 574902b8b5..18e3259f59 100644 --- a/src/secp256k1/.gitignore +++ b/src/secp256k1/.gitignore @@ -10,6 +10,7 @@ ctime_tests ecdh_example ecdsa_example schnorr_example +ellswift_example *.exe *.so *.a diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md index a2855912fd..0868e75480 100644 --- a/src/secp256k1/CHANGELOG.md +++ b/src/secp256k1/CHANGELOG.md @@ -5,7 +5,20 @@ 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.5.1] - 2024-08-01 + +#### Added + - Added usage example for an ElligatorSwift key exchange. + +#### Changed + - The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). + - "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly. + +#### Fixed + - Fixed compilation when the extrakeys module is disabled. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x. ## [0.5.0] - 2024-05-06 @@ -14,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Changed - The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations. - - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`ECMULT_GEN_KB` for CMake). + - The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake). - This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB). #### ABI Compatibility @@ -128,7 +141,7 @@ 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.5.0...HEAD +[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0 [0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt index 7e3465a75b..7a87686056 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/CMakeLists.txt @@ -1,11 +1,4 @@ -cmake_minimum_required(VERSION 3.13) - -if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) - # 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() +cmake_minimum_required(VERSION 3.16) project(libsecp256k1 # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of @@ -97,7 +90,7 @@ include(CheckStringOptionValue) check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) -set(SECP256K1_ECMULT_GEN_KB 22 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 22). [default=22]") +set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]") set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86) check_string_option_value(SECP256K1_ECMULT_GEN_KB) if(SECP256K1_ECMULT_GEN_KB EQUAL 2) @@ -185,7 +178,7 @@ else() 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}") + string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") endif() # Define custom "Coverage" build type. diff --git a/src/secp256k1/CONTRIBUTING.md b/src/secp256k1/CONTRIBUTING.md index 5fbf7332c9..a366d38b0e 100644 --- a/src/secp256k1/CONTRIBUTING.md +++ b/src/secp256k1/CONTRIBUTING.md @@ -49,6 +49,7 @@ In addition, libsecp256k1 tries to maintain the following coding conventions: * Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). * Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. * Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). +* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)). #### Style conventions diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index 322e44eaab..8723b53b2c 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -184,6 +184,17 @@ schnorr_example_LDFLAGS += -lbcrypt endif TESTS += schnorr_example endif +if ENABLE_MODULE_ELLSWIFT +noinst_PROGRAMS += ellswift_example +ellswift_example_SOURCES = examples/ellswift.c +ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC +ellswift_example_LDADD = libsecp256k1.la +ellswift_example_LDFLAGS = -static +if BUILD_WINDOWS +ellswift_example_LDFLAGS += -lbcrypt +endif +TESTS += ellswift_example +endif endif ### Precomputed tables diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index e8d4123ab9..ed93e0519e 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -82,7 +82,7 @@ To maintain a pristine source tree, CMake encourages to perform an out-of-source $ cmake .. $ cmake --build . $ ctest # run the test suite - $ sudo cmake --build . --target install # optional + $ sudo cmake --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. @@ -114,6 +114,7 @@ Usage examples can be found in the [examples](examples) directory. To compile th * [ECDSA example](examples/ecdsa.c) * [Schnorr signatures example](examples/schnorr.c) * [Deriving a shared secret (ECDH) example](examples/ecdh.c) + * [ElligatorSwift key exchange example](examples/ellswift.c) To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`. diff --git a/src/secp256k1/ci/ci.sh b/src/secp256k1/ci/ci.sh index c7d2e9e4ea..a6c608c29c 100755 --- a/src/secp256k1/ci/ci.sh +++ b/src/secp256k1/ci/ci.sh @@ -13,7 +13,7 @@ print_environment() { # does not rely on bash. for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ - EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \ + EXPERIMENTAL ECDH RECOVERY EXTRAKEYS SCHNORRSIG ELLSWIFT \ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ EXAMPLES \ HOST WRAPPER_CMD \ @@ -77,6 +77,7 @@ esac --with-ecmult-gen-kb="$ECMULTGENKB" \ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-ellswift="$ELLSWIFT" \ + --enable-module-extrakeys="$EXTRAKEYS" \ --enable-module-schnorrsig="$SCHNORRSIG" \ --enable-examples="$EXAMPLES" \ --enable-ctime-tests="$CTIMETESTS" \ diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index adae189787..6c4c11ddcd 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -6,7 +6,7 @@ AC_PREREQ([2.60]) define(_PKG_VERSION_MAJOR, 0) define(_PKG_VERSION_MINOR, 5) define(_PKG_VERSION_PATCH, 1) -define(_PKG_VERSION_IS_RELEASE, false) +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: @@ -216,9 +216,9 @@ AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE], AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86], [The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).] [Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.] -[The default value is a reasonable setting for desktop machines (currently 22). [default=22]] +[The default value is a reasonable setting for desktop machines (currently 86). [default=86]] )], -[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=22]) +[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86]) AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], [Build with extra checks for running inside Valgrind [default=auto]] diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md index cdf62430df..a64bae0f0d 100644 --- a/src/secp256k1/doc/release-process.md +++ b/src/secp256k1/doc/release-process.md @@ -31,7 +31,7 @@ Perform these checks when reviewing the release PR (see below): ```shell dir=$(mktemp -d) build=$(mktemp -d) - cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir + cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa ``` 4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. @@ -44,7 +44,8 @@ Perform these checks when reviewing the release PR (see below): 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) by * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), - * removing the `[Unreleased]` section header, and + * removing the `[Unreleased]` section header, + * ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and * including an entry for `### ABI Compatibility` if it doesn't exist, * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, * if this is not a patch release, diff --git a/src/secp256k1/examples/CMakeLists.txt b/src/secp256k1/examples/CMakeLists.txt index 607bb67770..fd1ebce395 100644 --- a/src/secp256k1/examples/CMakeLists.txt +++ b/src/secp256k1/examples/CMakeLists.txt @@ -28,3 +28,7 @@ endif() if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) add_example(schnorr) endif() + +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_example(ellswift) +endif() diff --git a/src/secp256k1/examples/ecdh.c b/src/secp256k1/examples/ecdh.c index 4b7b7d6154..d71fd2f604 100644 --- a/src/secp256k1/examples/ecdh.c +++ b/src/secp256k1/examples/ecdh.c @@ -108,7 +108,7 @@ int main(void) { /* 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 + * 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. * * Here we are preventing these writes from being optimized out, as any good compiler diff --git a/src/secp256k1/examples/ecdsa.c b/src/secp256k1/examples/ecdsa.c index d1d2b0e365..d5c4613d9c 100644 --- a/src/secp256k1/examples/ecdsa.c +++ b/src/secp256k1/examples/ecdsa.c @@ -128,7 +128,7 @@ int main(void) { /* 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 + * 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. * * Here we are preventing these writes from being optimized out, as any good compiler diff --git a/src/secp256k1/examples/ellswift.c b/src/secp256k1/examples/ellswift.c new file mode 100644 index 0000000000..52be7eebfb --- /dev/null +++ b/src/secp256k1/examples/ellswift.c @@ -0,0 +1,123 @@ +/************************************************************************* + * Written in 2024 by Sebastian Falbesoner * + * To the extent possible under law, the author(s) have dedicated all * + * copyright and related and neighboring rights to the software in this * + * file to the public domain worldwide. This software is distributed * + * without any warranty. For the CC0 Public Domain Dedication, see * + * EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 * + *************************************************************************/ + +/** This file demonstrates how to use the ElligatorSwift module to perform + * a key exchange according to BIP 324. Additionally, see the documentation + * in include/secp256k1_ellswift.h and doc/ellswift.md. + */ + +#include <stdio.h> +#include <assert.h> +#include <string.h> + +#include <secp256k1.h> +#include <secp256k1_ellswift.h> + +#include "examples_util.h" + +int main(void) { + secp256k1_context* ctx; + unsigned char randomize[32]; + unsigned char auxrand1[32]; + unsigned char auxrand2[32]; + unsigned char seckey1[32]; + unsigned char seckey2[32]; + unsigned char ellswift_pubkey1[64]; + unsigned char ellswift_pubkey2[64]; + unsigned char shared_secret1[32]; + unsigned char shared_secret2[32]; + int return_val; + + /* Create a secp256k1 context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (!fill_random(randomize, sizeof(randomize))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Randomizing the context is recommended to protect against side-channel + * leakage. See `secp256k1_context_randomize` in secp256k1.h for more + * information about it. This should never fail. */ + return_val = secp256k1_context_randomize(ctx, randomize); + assert(return_val); + + /*** Generate secret keys ***/ + + /* If the secret key is zero or out of range (bigger than secp256k1's + * order), we try to sample a new key. Note that the probability of this + * happening is negligible. */ + while (1) { + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) { + break; + } + } + + /* Generate ElligatorSwift public keys. This should never fail with valid context and + verified secret keys. Note that providing additional randomness (fourth parameter) is + optional, but recommended. */ + if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) { + printf("Failed to generate randomness\n"); + return 1; + } + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1); + assert(return_val); + return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2); + assert(return_val); + + /*** Create the shared secret on each side ***/ + + /* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail + * with a verified seckey and valid pubkey. Note that both parties pass both + * EllSwift pubkeys in the same order; the pubkey of the calling party is + * determined by the "party" boolean (sixth parameter). */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2, + seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail + * with a verified seckey and valid pubkey. */ + return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2, + seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, NULL); + assert(return_val); + + /* Both parties should end up with the same shared secret */ + return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1)); + assert(return_val == 0); + + printf( " Secret Key1: "); + print_hex(seckey1, sizeof(seckey1)); + printf( "EllSwift Pubkey1: "); + print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1)); + printf("\n Secret Key2: "); + print_hex(seckey2, sizeof(seckey2)); + printf( "EllSwift Pubkey2: "); + print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2)); + printf("\n Shared Secret: "); + print_hex(shared_secret1, sizeof(shared_secret1)); + + /* This will clear everything from the context and free the memory */ + secp256k1_context_destroy(ctx); + + /* 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. + * + * Here we are preventing these writes from being optimized out, as any good compiler + * will remove any writes that aren't used. */ + 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/schnorr.c b/src/secp256k1/examples/schnorr.c index 4c0dd1c1a9..b0409b986b 100644 --- a/src/secp256k1/examples/schnorr.c +++ b/src/secp256k1/examples/schnorr.c @@ -146,7 +146,7 @@ int main(void) { /* 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 + * 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. * * Here we are preventing these writes from being optimized out, as any good compiler diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 6b401e52c0..70c15f870b 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -6609,14 +6609,6 @@ static void permute(size_t *arr, size_t n) { } } -static void rand_pk(secp256k1_pubkey *pk) { - unsigned char seckey[32]; - secp256k1_keypair keypair; - testrand256(seckey); - CHECK(secp256k1_keypair_create(CTX, &keypair, seckey) == 1); - CHECK(secp256k1_keypair_pub(CTX, pk, &keypair) == 1); -} - static void test_sort_api(void) { secp256k1_pubkey pks[2]; const secp256k1_pubkey *pks_ptr[2]; @@ -6624,8 +6616,8 @@ static void test_sort_api(void) { pks_ptr[0] = &pks[0]; pks_ptr[1] = &pks[1]; - rand_pk(&pks[0]); - rand_pk(&pks[1]); + testutil_random_pubkey_test(&pks[0]); + testutil_random_pubkey_test(&pks[1]); CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2)); @@ -6678,7 +6670,7 @@ static void test_sort(void) { int j; const secp256k1_pubkey *pk_ptr[5]; for (j = 0; j < 5; j++) { - rand_pk(&pk[j]); + testutil_random_pubkey_test(&pk[j]); pk_ptr[j] = &pk[j]; } secp256k1_ec_pubkey_sort(CTX, pk_ptr, 5); diff --git a/src/secp256k1/src/testutil.h b/src/secp256k1/src/testutil.h index 8296a5fb99..fc56854dd3 100644 --- a/src/secp256k1/src/testutil.h +++ b/src/secp256k1/src/testutil.h @@ -107,6 +107,12 @@ static void testutil_random_gej_test(secp256k1_gej *gej) { testutil_random_ge_jacobian_test(gej, &ge); } +static void testutil_random_pubkey_test(secp256k1_pubkey *pk) { + secp256k1_ge ge; + testutil_random_ge_test(&ge); + secp256k1_pubkey_save(pk, &ge); +} + static void testutil_random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; diff --git a/src/serialize.h b/src/serialize.h index 35519056a5..2af998f3c5 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1061,7 +1061,7 @@ protected: size_t nSize{0}; public: - SizeComputer() {} + SizeComputer() = default; void write(Span<const std::byte> src) { diff --git a/src/streams.h b/src/streams.h index 57fc600646..c2a9dea287 100644 --- a/src/streams.h +++ b/src/streams.h @@ -161,7 +161,7 @@ public: typedef vector_type::const_iterator const_iterator; typedef vector_type::reverse_iterator reverse_iterator; - explicit DataStream() {} + explicit DataStream() = default; explicit DataStream(Span<const uint8_t> sp) : DataStream{AsBytes(sp)} {} explicit DataStream(Span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {} diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp index a8ddcd793f..4e370f1516 100644 --- a/src/support/cleanse.cpp +++ b/src/support/cleanse.cpp @@ -7,14 +7,14 @@ #include <cstring> -#if defined(_MSC_VER) -#include <Windows.h> // For SecureZeroMemory. +#if defined(WIN32) +#include <windows.h> #endif void memory_cleanse(void *ptr, size_t len) { -#if defined(_MSC_VER) - /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ +#if defined(WIN32) + /* SecureZeroMemory is guaranteed not to be optimized out. */ SecureZeroMemory(ptr, len); #else std::memset(ptr, 0, len); diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index fe3ba38cde..01eef2b93d 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -46,9 +46,7 @@ Arena::Arena(void *base_in, size_t size_in, size_t alignment_in): chunks_free_end.emplace(static_cast<char*>(base) + size_in, it); } -Arena::~Arena() -{ -} +Arena::~Arena() = default; void* Arena::alloc(size_t size) { diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h index 81e0df513a..2363b1e4ef 100644 --- a/src/support/lockedpool.h +++ b/src/support/lockedpool.h @@ -19,7 +19,7 @@ class LockedPageAllocator { public: - virtual ~LockedPageAllocator() {} + virtual ~LockedPageAllocator() = default; /** Allocate and lock memory pages. * If len is not a multiple of the system page size, it is rounded up. * Returns nullptr in case of allocation failure. diff --git a/src/sync.h b/src/sync.h index dc63e3f2d0..b22956ef1a 100644 --- a/src/sync.h +++ b/src/sync.h @@ -206,7 +206,7 @@ public: protected: // needed for reverse_lock - UniqueLock() { } + UniqueLock() = default; public: /** diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp index 5f0318e8c4..297595a9cf 100644 --- a/src/test/argsman_tests.cpp +++ b/src/test/argsman_tests.cpp @@ -644,10 +644,12 @@ BOOST_AUTO_TEST_CASE(util_GetChainTypeString) { TestArgsManager test_args; const auto testnet = std::make_pair("-testnet", ArgsManager::ALLOW_ANY); + const auto testnet4 = std::make_pair("-testnet4", ArgsManager::ALLOW_ANY); const auto regtest = std::make_pair("-regtest", ArgsManager::ALLOW_ANY); - test_args.SetupArgs({testnet, regtest}); + test_args.SetupArgs({testnet, testnet4, regtest}); const char* argv_testnet[] = {"cmd", "-testnet"}; + const char* argv_testnet4[] = {"cmd", "-testnet4"}; const char* argv_regtest[] = {"cmd", "-regtest"}; const char* argv_test_no_reg[] = {"cmd", "-testnet", "-noregtest"}; const char* argv_both[] = {"cmd", "-testnet", "-regtest"}; @@ -663,6 +665,12 @@ BOOST_AUTO_TEST_CASE(util_GetChainTypeString) BOOST_CHECK(test_args.ParseParameters(2, argv_testnet, error)); BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test"); + BOOST_CHECK(test_args.ParseParameters(0, argv_testnet4, error)); + BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "main"); + + BOOST_CHECK(test_args.ParseParameters(2, argv_testnet4, error)); + BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "testnet4"); + BOOST_CHECK(test_args.ParseParameters(2, argv_regtest, error)); BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "regtest"); @@ -758,8 +766,8 @@ struct ArgsMergeTestingSetup : public BasicTestingSetup { ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] { for (bool soft_set : {false, true}) { for (bool force_set : {false, true}) { - for (const std::string& section : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::SIGNET)}) { - for (const std::string& network : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::SIGNET)}) { + for (const std::string& section : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::TESTNET4), ChainTypeToString(ChainType::SIGNET)}) { + for (const std::string& network : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::TESTNET4), ChainTypeToString(ChainType::SIGNET)}) { for (bool net_specific : {false, true}) { fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific); } @@ -913,7 +921,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup) // Results file is formatted like: // // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output> - BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82"); + BOOST_CHECK_EQUAL(out_sha_hex, "f1ee5ab094cc43d16a6086fa7f2c10389e0f99902616b31bbf29189972ad1473"); } // Similar test as above, but for ArgsManager::GetChainTypeString function. @@ -1016,7 +1024,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup) // Results file is formatted like: // // <input> || <output> - BOOST_CHECK_EQUAL(out_sha_hex, "f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c"); + BOOST_CHECK_EQUAL(out_sha_hex, "9e60306e1363528bbc19a47f22bcede88e5d6815212f18ec8e6cdc4638dddab4"); } BOOST_AUTO_TEST_CASE(util_ReadWriteSettings) diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 10028c7c93..f178499299 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <arith_uint256.h> +#include <test/util/setup_common.h> #include <uint256.h> #include <boost/test/unit_test.hpp> @@ -22,7 +23,8 @@ static inline arith_uint256 arith_uint256V(const std::vector<unsigned char>& vch { return UintToArith256(uint256(vch)); } -static inline arith_uint256 arith_uint256S(const std::string& str) { return UintToArith256(uint256S(str)); } +// Takes a number written in hex (with most significant digits first). +static inline arith_uint256 arith_uint256S(std::string_view str) { return UintToArith256(uint256S(str)); } const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" @@ -104,6 +106,7 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality BOOST_CHECK(arith_uint256S(R1L.ToString()) == R1L); BOOST_CHECK(arith_uint256S(" 0x" + R1L.ToString() + " ") == R1L); BOOST_CHECK(arith_uint256S("") == ZeroL); + BOOST_CHECK(arith_uint256S("1") == OneL); BOOST_CHECK(R1L == arith_uint256S(R1ArrayHex)); BOOST_CHECK(arith_uint256(R1L) == R1L); BOOST_CHECK((arith_uint256(R1L^R2L)^R2L) == R1L); @@ -278,6 +281,12 @@ BOOST_AUTO_TEST_CASE( comparison ) // <= >= < > BOOST_CHECK( R1L <= TmpL ); BOOST_CHECK( (R1L == TmpL) != (R1L < TmpL)); BOOST_CHECK( (TmpL == R1L) || !( R1L >= TmpL)); BOOST_CHECK(! (TmpL < R1L)); BOOST_CHECK(! (R1L > TmpL)); } + + BOOST_CHECK_LT(ZeroL, + OneL); + // Verify hex number representation has the most significant digits first. + BOOST_CHECK_LT(arith_uint256S("0000000000000000000000000000000000000000000000000000000000000001"), + arith_uint256S("1000000000000000000000000000000000000000000000000000000000000000")); } BOOST_AUTO_TEST_CASE( plusMinus ) diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index 9b8f419290..4ecc15041c 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -5,7 +5,9 @@ #include <boost/test/unit_test.hpp> #include <chain.h> +#include <node/blockstorage.h> #include <rpc/blockchain.h> +#include <sync.h> #include <test/util/setup_common.h> #include <util/string.h> @@ -76,4 +78,43 @@ BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target) TestDifficulty(0x12345678, 5913134931067755359633408.0); } +//! Prune chain from height down to genesis block and check that +//! GetPruneHeight returns the correct value +static void CheckGetPruneHeight(node::BlockManager& blockman, CChain& chain, int height) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) +{ + AssertLockHeld(::cs_main); + + // Emulate pruning all blocks from `height` down to the genesis block + // by unsetting the `BLOCK_HAVE_DATA` flag from `nStatus` + for (CBlockIndex* it{chain[height]}; it != nullptr && it->nHeight > 0; it = it->pprev) { + it->nStatus &= ~BLOCK_HAVE_DATA; + } + + const auto prune_height{GetPruneHeight(blockman, chain)}; + BOOST_REQUIRE(prune_height.has_value()); + BOOST_CHECK_EQUAL(*prune_height, height); +} + +BOOST_FIXTURE_TEST_CASE(get_prune_height, TestChain100Setup) +{ + LOCK(::cs_main); + auto& chain = m_node.chainman->ActiveChain(); + auto& blockman = m_node.chainman->m_blockman; + + // Fresh chain of 100 blocks without any pruned blocks, so std::nullopt should be returned + BOOST_CHECK(!GetPruneHeight(blockman, chain).has_value()); + + // Start pruning + CheckGetPruneHeight(blockman, chain, 1); + CheckGetPruneHeight(blockman, chain, 99); + CheckGetPruneHeight(blockman, chain, 100); +} + +BOOST_AUTO_TEST_CASE(num_chain_tx_max) +{ + CBlockIndex block_index{}; + block_index.m_chain_tx_count = std::numeric_limits<uint64_t>::max(); + BOOST_CHECK_EQUAL(block_index.m_chain_tx_count, std::numeric_limits<uint64_t>::max()); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index b372f25ea9..470fdde30a 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -149,8 +149,7 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) unsigned int pos = 0; /*int block_height =*/ test[pos++].getInt<int>(); - uint256 block_hash; - BOOST_CHECK(ParseHashStr(test[pos++].get_str(), block_hash)); + BOOST_CHECK(uint256::FromHex(test[pos++].get_str())); CBlock block; BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str())); @@ -165,11 +164,9 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) tx_undo.vprevout.emplace_back(txout, 0, false); } - uint256 prev_filter_header_basic; - BOOST_CHECK(ParseHashStr(test[pos++].get_str(), prev_filter_header_basic)); + uint256 prev_filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))}; std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str()); - uint256 filter_header_basic; - BOOST_CHECK(ParseHashStr(test[pos++].get_str(), filter_header_basic)); + uint256 filter_header_basic{*Assert(uint256::FromHex(test[pos++].get_str()))}; BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo); BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic); diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp index 9eb7acc3ca..121f00bd25 100644 --- a/src/test/blockmanager_tests.cpp +++ b/src/test/blockmanager_tests.cpp @@ -2,6 +2,7 @@ // 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 <clientversion.h> #include <node/blockstorage.h> @@ -113,7 +114,7 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup) }; // 1) Return genesis block when all blocks are available - BOOST_CHECK_EQUAL(blockman.GetFirstStoredBlock(tip), chainman->ActiveChain()[0]); + BOOST_CHECK_EQUAL(blockman.GetFirstBlock(tip, BLOCK_HAVE_DATA), chainman->ActiveChain()[0]); BOOST_CHECK(blockman.CheckBlockDataAvailability(tip, *chainman->ActiveChain()[0])); // 2) Check lower_block when all blocks are available @@ -127,7 +128,7 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup) func_prune_blocks(last_pruned_block); // 3) The last block not pruned is in-between upper-block and the genesis block - BOOST_CHECK_EQUAL(blockman.GetFirstStoredBlock(tip), first_available_block); + BOOST_CHECK_EQUAL(blockman.GetFirstBlock(tip, BLOCK_HAVE_DATA), first_available_block); BOOST_CHECK(blockman.CheckBlockDataAvailability(tip, *first_available_block)); BOOST_CHECK(!blockman.CheckBlockDataAvailability(tip, *last_pruned_block)); } diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index cbf85277a8..0c6e2e752d 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) CTransaction spendingTx(deserialize, TX_WITH_WITNESS, spendStream); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(uint256S("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")); + filter.insert(uint256{"b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"}); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); @@ -138,11 +138,11 @@ BOOST_AUTO_TEST_CASE(bloom_match) BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(COutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + filter.insert(COutPoint(Txid::FromHex("90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b").value(), 0)); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - COutPoint prevOutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); + COutPoint prevOutPoint(Txid::FromHex("90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b").value(), 0); { std::vector<unsigned char> data(32 + sizeof(unsigned int)); memcpy(data.data(), prevOutPoint.hash.begin(), 32); @@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(uint256S("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")); + filter.insert(uint256{"00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"}); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); @@ -160,11 +160,11 @@ BOOST_AUTO_TEST_CASE(bloom_match) BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(COutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1)); + filter.insert(COutPoint(Txid::FromHex("90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b").value(), 1)); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(COutPoint(TxidFromString("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); + filter.insert(COutPoint(Txid::FromHex("000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b").value(), 0)); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about"); } @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) CBlock block = getBlock13b8a(); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the last transaction - filter.insert(uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + filter.insert(uint256{"74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"}); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex()); @@ -181,7 +181,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 1U); std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0]; - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); std::vector<uint256> vMatched; @@ -192,7 +192,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Also match the 8th transaction - filter.insert(uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + filter.insert(uint256{"dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"}); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the first transaction - filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + filter.insert(uint256{"e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"}); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0]; - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector<uint256> vMatched; @@ -251,13 +251,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); - BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256{"28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"}); BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); - BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256{"6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2"}); BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2); - BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256{"3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"}); BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); // Match the first transaction - filter.insert(uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + filter.insert(uint256{"e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"}); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0]; - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector<uint256> vMatched; @@ -308,10 +308,10 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); - BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")); + BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256{"28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f"}); BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); - BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")); + BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256{"3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23"}); BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); @@ -332,14 +332,14 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the only transaction - filter.insert(uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + filter.insert(uint256{"63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"}); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector<uint256> vMatched; @@ -370,7 +370,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the last transaction - filter.insert(uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + filter.insert(uint256{"0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"}); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); @@ -378,7 +378,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0]; - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); std::vector<uint256> vMatched; @@ -389,13 +389,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Also match the 4th transaction - filter.insert(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + filter.insert(uint256{"02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"}); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); - BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); + BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256{"02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"}); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3); BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); @@ -426,9 +426,9 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We should match the generation outpoint - BOOST_CHECK(filter.contains(COutPoint(TxidFromString("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); + BOOST_CHECK(filter.contains(COutPoint(Txid::FromHex("147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b").value(), 0))); // ... but not the 4th transaction's output (its not pay-2-pubkey) - BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); + BOOST_CHECK(!filter.contains(COutPoint(Txid::FromHex("02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041").value(), 0))); } BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) @@ -451,8 +451,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We shouldn't match any outpoints (UPDATE_NONE) - BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0))); - BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0))); + BOOST_CHECK(!filter.contains(COutPoint(Txid::FromHex("147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b").value(), 0))); + BOOST_CHECK(!filter.contains(COutPoint(Txid::FromHex("02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041").value(), 0))); } static std::vector<unsigned char> RandomData() @@ -463,8 +463,7 @@ static std::vector<unsigned char> RandomData() BOOST_AUTO_TEST_CASE(rolling_bloom) { - SeedInsecureRand(SeedRand::ZEROS); - g_mock_deterministic_tests = true; + SeedRandomForTest(SeedRand::ZEROS); // last-100-entry, 1% false positive: CRollingBloomFilter rb1(100, 0.01); @@ -491,7 +490,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) ++nHits; } // Expect about 100 hits - BOOST_CHECK_EQUAL(nHits, 75U); + BOOST_CHECK_EQUAL(nHits, 71U); BOOST_CHECK(rb1.contains(data[DATASIZE-1])); rb1.reset(); @@ -519,7 +518,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) ++nHits; } // Expect about 5 false positives - BOOST_CHECK_EQUAL(nHits, 6U); + BOOST_CHECK_EQUAL(nHits, 3U); // last-1000-entry, 0.01% false positive: CRollingBloomFilter rb2(1000, 0.001); @@ -530,7 +529,6 @@ BOOST_AUTO_TEST_CASE(rolling_bloom) for (int i = 0; i < DATASIZE; i++) { BOOST_CHECK(rb2.contains(data[i])); } - g_mock_deterministic_tests = false; } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 023a5e8e70..7810d91a77 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -28,7 +28,7 @@ struct NoLockLoggingTestingSetup : public TestingSetup { NoLockLoggingTestingSetup() #ifdef DEBUG_LOCKCONTENTION - : TestingSetup{ChainType::MAIN, /*extra_args=*/{"-debugexclude=lock"}} {} + : TestingSetup{ChainType::MAIN, {.extra_args = { "-debugexclude=lock" } }} {} #else : TestingSetup{ChainType::MAIN} {} #endif diff --git a/src/test/cluster_linearize_tests.cpp b/src/test/cluster_linearize_tests.cpp new file mode 100644 index 0000000000..d15e783ea1 --- /dev/null +++ b/src/test/cluster_linearize_tests.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 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 <cluster_linearize.h> +#include <test/util/cluster_linearize.h> +#include <test/util/setup_common.h> +#include <util/bitset.h> +#include <util/strencodings.h> + +#include <vector> + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(cluster_linearize_tests, BasicTestingSetup) + +using namespace cluster_linearize; + +namespace { + +template<typename SetType> +void TestDepGraphSerialization(const Cluster<SetType>& cluster, const std::string& hexenc) +{ + DepGraph depgraph(cluster); + + // Run normal sanity and correspondence checks, which includes a round-trip test. + VerifyDepGraphFromCluster(cluster, depgraph); + + // There may be multiple serializations of the same graph, but DepGraphFormatter's serializer + // only produces one of those. Verify that hexenc matches that canonical serialization. + std::vector<unsigned char> encoding; + VectorWriter writer(encoding, 0); + writer << Using<DepGraphFormatter>(depgraph); + BOOST_CHECK_EQUAL(HexStr(encoding), hexenc); + + // Test that deserializing that encoding yields depgraph. This is effectively already implied + // by the round-trip test above (if depgraph is acyclic), but verify it explicitly again here. + SpanReader reader(encoding); + DepGraph<SetType> depgraph_read; + reader >> Using<DepGraphFormatter>(depgraph_read); + BOOST_CHECK(depgraph == depgraph_read); +} + +} // namespace + +BOOST_AUTO_TEST_CASE(depgraph_ser_tests) +{ + // Empty cluster. + TestDepGraphSerialization<TestBitSet>( + {}, + "00" /* end of graph */); + + // Transactions: A(fee=0,size=1). + TestDepGraphSerialization<TestBitSet>( + {{{0, 1}, {}}}, + "01" /* A size */ + "00" /* A fee */ + "00" /* A insertion position (no skips): A */ + "00" /* end of graph */); + + // Transactions: A(fee=42,size=11), B(fee=-13,size=7), B depends on A. + TestDepGraphSerialization<TestBitSet>( + {{{42, 11}, {}}, {{-13, 7}, {0}}}, + "0b" /* A size */ + "54" /* A fee */ + "00" /* A insertion position (no skips): A */ + "07" /* B size */ + "19" /* B fee */ + "00" /* B->A dependency (no skips) */ + "00" /* B insertion position (no skips): A,B */ + "00" /* end of graph */); + + // Transactions: A(64,128), B(128,256), C(1,1), C depends on A and B. + TestDepGraphSerialization<TestBitSet>( + {{{64, 128}, {}}, {{128, 256}, {}}, {{1, 1}, {0, 1}}}, + "8000" /* A size */ + "8000" /* A fee */ + "00" /* A insertion position (no skips): A */ + "8100" /* B size */ + "8100" /* B fee */ + "01" /* B insertion position (skip B->A dependency): A,B */ + "01" /* C size */ + "02" /* C fee */ + "00" /* C->B dependency (no skips) */ + "00" /* C->A dependency (no skips) */ + "00" /* C insertion position (no skips): A,B,C */ + "00" /* end of graph */); + + // Transactions: A(-57,113), B(57,114), C(-58,115), D(58,116). Deps: B->A, C->A, D->C, in order + // [B,A,C,D]. This exercises non-topological ordering (internally serialized as A,B,C,D). + TestDepGraphSerialization<TestBitSet>( + {{{57, 114}, {1}}, {{-57, 113}, {}}, {{-58, 115}, {1}}, {{58, 116}, {2}}}, + "71" /* A size */ + "71" /* A fee */ + "00" /* A insertion position (no skips): A */ + "72" /* B size */ + "72" /* B fee */ + "00" /* B->A dependency (no skips) */ + "01" /* B insertion position (skip A): B,A */ + "73" /* C size */ + "73" /* C fee */ + "01" /* C->A dependency (skip C->B dependency) */ + "00" /* C insertion position (no skips): B,A,C */ + "74" /* D size */ + "74" /* D fee */ + "00" /* D->C dependency (no skips) */ + "01" /* D insertion position (skip D->B dependency, D->A is implied): B,A,C,D */ + "00" /* end of graph */); + + // Transactions: A(1,2), B(3,1), C(2,1), D(1,3), E(1,1). Deps: C->A, D->A, D->B, E->D. + // In order: [D,A,B,E,C]. Internally serialized in order A,B,C,D,E. + TestDepGraphSerialization<TestBitSet>( + {{{1, 3}, {1, 2}}, {{1, 2}, {}}, {{3, 1}, {}}, {{1, 1}, {0}}, {{2, 1}, {1}}}, + "02" /* A size */ + "02" /* A fee */ + "00" /* A insertion position (no skips): A */ + "01" /* B size */ + "06" /* B fee */ + "01" /* B insertion position (skip B->A dependency): A,B */ + "01" /* C size */ + "04" /* C fee */ + "01" /* C->A dependency (skip C->B dependency) */ + "00" /* C insertion position (no skips): A,B,C */ + "03" /* D size */ + "02" /* D fee */ + "01" /* D->B dependency (skip D->C dependency) */ + "00" /* D->A dependency (no skips) */ + "03" /* D insertion position (skip C,B,A): D,A,B,C */ + "01" /* E size */ + "02" /* E fee */ + "00" /* E->D dependency (no skips) */ + "02" /* E insertion position (skip E->C dependency, E->B and E->A are implied, + skip insertion C): D,A,B,E,C */ + "00" /* end of graph */ + ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index b6d3e7d567..fb929a2b0e 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -55,10 +55,10 @@ public: uint256 GetBestBlock() const override { return hashBestBlock_; } - bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock, bool erase = true) override + bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override { - for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = erase ? mapCoins.erase(it) : std::next(it)) { - if (it->second.flags & CCoinsCacheEntry::DIRTY) { + for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)){ + if (it->second.IsDirty()) { // Same optimization used in CCoinsViewDB is to only write dirty entries. map_[it->first] = it->second.coin; if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) { @@ -78,7 +78,7 @@ class CCoinsViewCacheTest : public CCoinsViewCache public: explicit CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {} - void SelfTest() const + void SelfTest(bool sanity_check = true) const { // Manually recompute the dynamic usage of the whole data, and compare it. size_t ret = memusage::DynamicUsage(cacheCoins); @@ -89,9 +89,13 @@ public: } BOOST_CHECK_EQUAL(GetCacheSize(), count); BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); + if (sanity_check) { + SanityCheck(); + } } CCoinsMap& map() const { return cacheCoins; } + CoinsCachePair& sentinel() const { return m_sentinel; } size_t& usage() const { return cachedCoinsUsage; } }; @@ -307,8 +311,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { // has the expected effect (the other duplicate is overwritten at all cache levels) BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) { - SeedInsecureRand(SeedRand::ZEROS); - g_mock_deterministic_tests = true; + SeedRandomForTest(SeedRand::ZEROS); bool spent_a_duplicate_coinbase = false; // A simple map to track what we expect the cache stack to represent. @@ -496,8 +499,6 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) // Verify coverage. BOOST_CHECK(spent_a_duplicate_coinbase); - - g_mock_deterministic_tests = false; } BOOST_AUTO_TEST_CASE(ccoins_serialization) @@ -579,7 +580,7 @@ static void SetCoinsValue(CAmount value, Coin& coin) } } -static size_t InsertCoinsMapEntry(CCoinsMap& map, CAmount value, char flags) +static size_t InsertCoinsMapEntry(CCoinsMap& map, CoinsCachePair& sentinel, CAmount value, char flags) { if (value == ABSENT) { assert(flags == NO_ENTRY); @@ -587,10 +588,10 @@ static size_t InsertCoinsMapEntry(CCoinsMap& map, CAmount value, char flags) } assert(flags != NO_ENTRY); CCoinsCacheEntry entry; - entry.flags = flags; SetCoinsValue(value, entry.coin); auto inserted = map.emplace(OUTPOINT, std::move(entry)); assert(inserted.second); + inserted.first->second.AddFlags(flags, *inserted.first, sentinel); return inserted.first->second.coin.DynamicMemoryUsage(); } @@ -606,17 +607,20 @@ void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags, const C } else { value = it->second.coin.out.nValue; } - flags = it->second.flags; + flags = it->second.GetFlags(); assert(flags != NO_ENTRY); } } void WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags) { + CoinsCachePair sentinel{}; + sentinel.second.SelfRef(sentinel); CCoinsMapMemoryResource resource; CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource}; - InsertCoinsMapEntry(map, value, flags); - BOOST_CHECK(view.BatchWrite(map, {})); + auto usage{InsertCoinsMapEntry(map, sentinel, value, flags)}; + auto cursor{CoinsViewCacheCursor(usage, sentinel, map, /*will_erase=*/true)}; + BOOST_CHECK(view.BatchWrite(cursor, {})); } class SingleEntryCacheTest @@ -625,7 +629,7 @@ public: SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags) { WriteCoinsViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY); - cache.usage() += InsertCoinsMapEntry(cache.map(), cache_value, cache_flags); + cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), cache_value, cache_flags); } CCoinsView root; @@ -637,7 +641,7 @@ static void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount exp { SingleEntryCacheTest test(base_value, cache_value, cache_flags); test.cache.AccessCoin(OUTPOINT); - test.cache.SelfTest(); + test.cache.SelfTest(/*sanity_check=*/false); CAmount result_value; char result_flags; @@ -806,7 +810,7 @@ void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected char result_flags; try { WriteCoinsViewEntry(test.cache, child_value, child_flags); - test.cache.SelfTest(); + test.cache.SelfTest(/*sanity_check=*/false); GetCoinsMapEntry(test.cache.map(), result_value, result_flags); } catch (std::logic_error&) { result_value = FAIL; @@ -919,6 +923,7 @@ void TestFlushBehavior( // 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; + cache->SanityCheck(); // hashBlock must be filled before flushing to disk; value is // unimportant here. This is normally done during connect/disconnect block. cache->SetBestBlock(InsecureRand256()); diff --git a/src/test/coinscachepair_tests.cpp b/src/test/coinscachepair_tests.cpp new file mode 100644 index 0000000000..61840f1f09 --- /dev/null +++ b/src/test/coinscachepair_tests.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2024-present 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 <boost/test/unit_test.hpp> + +#include <list> + +BOOST_AUTO_TEST_SUITE(coinscachepair_tests) + +static constexpr auto NUM_NODES{4}; + +std::list<CoinsCachePair> CreatePairs(CoinsCachePair& sentinel) +{ + std::list<CoinsCachePair> nodes; + for (auto i{0}; i < NUM_NODES; ++i) { + nodes.emplace_back(); + + auto node{std::prev(nodes.end())}; + node->second.AddFlags(CCoinsCacheEntry::DIRTY, *node, sentinel); + + BOOST_CHECK_EQUAL(node->second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(node->second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*node)); + + if (i > 0) { + BOOST_CHECK_EQUAL(std::prev(node)->second.Next(), &(*node)); + BOOST_CHECK_EQUAL(node->second.Prev(), &(*std::prev(node))); + } + } + return nodes; +} + +BOOST_AUTO_TEST_CASE(linked_list_iteration) +{ + CoinsCachePair sentinel; + sentinel.second.SelfRef(sentinel); + auto nodes{CreatePairs(sentinel)}; + + // Check iterating through pairs is identical to iterating through a list + auto node{sentinel.second.Next()}; + for (const auto& expected : nodes) { + BOOST_CHECK_EQUAL(&expected, node); + node = node->second.Next(); + } + BOOST_CHECK_EQUAL(node, &sentinel); + + // Check iterating through pairs is identical to iterating through a list + // Clear the flags during iteration + node = sentinel.second.Next(); + for (const auto& expected : nodes) { + BOOST_CHECK_EQUAL(&expected, node); + auto next = node->second.Next(); + node->second.ClearFlags(); + node = next; + } + BOOST_CHECK_EQUAL(node, &sentinel); + // Check that sentinel's next and prev are itself + BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel); + + // Delete the nodes from the list to make sure there are no dangling pointers + for (auto it{nodes.begin()}; it != nodes.end(); it = nodes.erase(it)) { + BOOST_CHECK_EQUAL(it->second.GetFlags(), 0); + } +} + +BOOST_AUTO_TEST_CASE(linked_list_iterate_erase) +{ + CoinsCachePair sentinel; + sentinel.second.SelfRef(sentinel); + auto nodes{CreatePairs(sentinel)}; + + // Check iterating through pairs is identical to iterating through a list + // Erase the nodes as we iterate through, but don't clear flags + // The flags will be cleared by the CCoinsCacheEntry's destructor + auto node{sentinel.second.Next()}; + for (auto expected{nodes.begin()}; expected != nodes.end(); expected = nodes.erase(expected)) { + BOOST_CHECK_EQUAL(&(*expected), node); + node = node->second.Next(); + } + BOOST_CHECK_EQUAL(node, &sentinel); + + // Check that sentinel's next and prev are itself + BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel); +} + +BOOST_AUTO_TEST_CASE(linked_list_random_deletion) +{ + CoinsCachePair sentinel; + sentinel.second.SelfRef(sentinel); + auto nodes{CreatePairs(sentinel)}; + + // Create linked list sentinel->n1->n2->n3->n4->sentinel + auto n1{nodes.begin()}; + auto n2{std::next(n1)}; + auto n3{std::next(n2)}; + auto n4{std::next(n3)}; + + // Delete n2 + // sentinel->n1->n3->n4->sentinel + nodes.erase(n2); + // Check that n1 now points to n3, and n3 still points to n4 + // Also check that flags were not altered + BOOST_CHECK_EQUAL(n1->second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(n1->second.Next(), &(*n3)); + BOOST_CHECK_EQUAL(n3->second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4)); + BOOST_CHECK_EQUAL(n3->second.Prev(), &(*n1)); + + // Delete n1 + // sentinel->n3->n4->sentinel + nodes.erase(n1); + // Check that sentinel now points to n3, and n3 still points to n4 + // Also check that flags were not altered + BOOST_CHECK_EQUAL(n3->second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3)); + BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4)); + BOOST_CHECK_EQUAL(n3->second.Prev(), &sentinel); + + // Delete n4 + // sentinel->n3->sentinel + nodes.erase(n4); + // Check that sentinel still points to n3, and n3 points to sentinel + // Also check that flags were not altered + BOOST_CHECK_EQUAL(n3->second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3)); + BOOST_CHECK_EQUAL(n3->second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*n3)); + + // Delete n3 + // sentinel->sentinel + nodes.erase(n3); + // Check that sentinel's next and prev are itself + BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel); +} + +BOOST_AUTO_TEST_CASE(linked_list_add_flags) +{ + CoinsCachePair sentinel; + sentinel.second.SelfRef(sentinel); + CoinsCachePair n1; + CoinsCachePair n2; + + // Check that adding 0 flag has no effect + n1.second.AddFlags(0, n1, sentinel); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), 0); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel); + + // Check that adding DIRTY flag inserts it into linked list and sets flags + n1.second.AddFlags(CCoinsCacheEntry::DIRTY, n1, sentinel); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1); + + // Check that adding FRESH flag on new node inserts it after n1 + n2.second.AddFlags(CCoinsCacheEntry::FRESH, n2, sentinel); + BOOST_CHECK_EQUAL(n2.second.GetFlags(), CCoinsCacheEntry::FRESH); + BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(n2.second.Prev(), &n1); + BOOST_CHECK_EQUAL(n1.second.Next(), &n2); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2); + + // Check that adding 0 flag has no effect, and doesn't change position + n1.second.AddFlags(0, n1, sentinel); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(n1.second.Next(), &n2); + BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1); + BOOST_CHECK_EQUAL(n2.second.Prev(), &n1); + + // Check that we can add extra flags, but they don't change our position + n1.second.AddFlags(CCoinsCacheEntry::FRESH, n1, sentinel); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH); + BOOST_CHECK_EQUAL(n1.second.Next(), &n2); + BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1); + BOOST_CHECK_EQUAL(n2.second.Prev(), &n1); + + // Check that we can clear flags then re-add them + n1.second.ClearFlags(); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), 0); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2); + BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel); + + // Check that calling `ClearFlags` with 0 flags has no effect + n1.second.ClearFlags(); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), 0); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2); + BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel); + + // Adding 0 still has no effect + n1.second.AddFlags(0, n1, sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2); + BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel); + + // But adding DIRTY re-inserts it after n2 + n1.second.AddFlags(CCoinsCacheEntry::DIRTY, n1, sentinel); + BOOST_CHECK_EQUAL(n1.second.GetFlags(), CCoinsCacheEntry::DIRTY); + BOOST_CHECK_EQUAL(n2.second.Next(), &n1); + BOOST_CHECK_EQUAL(n1.second.Prev(), &n2); + BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel); + BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 46acc6fc9f..f84e04e819 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -1195,7 +1195,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests) uint256 res; int table[4]; for (int i = 0; i < 4; ++i) { - table[i] = g_insecure_rand_ctx.randbits(3); + table[i] = g_insecure_rand_ctx.randbits<3>(); } for (int order = 0; order < 4; ++order) { MuHash3072 acc; @@ -1215,8 +1215,8 @@ BOOST_AUTO_TEST_CASE(muhash_tests) } } - MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X - MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X, y=Y + MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X + MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X, y=Y MuHash3072 z; // x=X, y=Y, z=1 z *= x; // x=X, y=Y, z=X z *= y; // x=X, y=Y, z=X*Y @@ -1235,7 +1235,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests) acc *= FromInt(1); acc /= FromInt(2); acc.Finalize(out); - BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")); + BOOST_CHECK_EQUAL(out, uint256{"10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"}); MuHash3072 acc2 = FromInt(0); unsigned char tmp[32] = {1, 0}; @@ -1243,7 +1243,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests) unsigned char tmp2[32] = {2, 0}; acc2.Remove(tmp2); acc2.Finalize(out); - BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")); + BOOST_CHECK_EQUAL(out, uint256{"10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"}); // Test MuHash3072 serialization MuHash3072 serchk = FromInt(1); serchk *= FromInt(2); diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index eafbcf5681..fc22daeb57 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -33,11 +33,11 @@ BOOST_AUTO_TEST_SUITE(cuckoocache_tests); /* Test that no values not inserted into the cache are read out of it. * - * There are no repeats in the first 200000 insecure_GetRandHash calls + * There are no repeats in the first 200000 InsecureRand256() calls */ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) { - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); CuckooCache::cache<uint256, SignatureCacheHasher> cc{}; size_t megabytes = 4; cc.setup_bytes(megabytes << 20); @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) template <typename Cache> static double test_cache(size_t megabytes, double load) { - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); std::vector<uint256> hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); @@ -126,7 +126,7 @@ template <typename Cache> static void test_cache_erase(size_t megabytes) { double load = 1; - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); std::vector<uint256> hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); @@ -189,7 +189,7 @@ template <typename Cache> static void test_cache_erase_parallel(size_t megabytes) { double load = 1; - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); std::vector<uint256> hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); @@ -293,7 +293,7 @@ static void test_cache_generations() // iterations with non-deterministic values, so it isn't "overfit" to the // specific entropy in FastRandomContext(true) and implementation of the // cache. - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); // block_activity models a chunk of network activity. n_insert elements are // added to the cache. The first and last n/4 are stored for removal later diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index e6821dd321..01b13fa794 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -441,20 +441,20 @@ BOOST_FIXTURE_TEST_SUITE(descriptor_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(descriptor_test) { // Basic single-key compressed - Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt, /*op_desc_id=*/uint256S("8ef71f7b6ac0918663f6706be469d6109f6922e21f484009d7ab49d77da36e8b")); - Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt, /*op_desc_id=*/uint256S("5fe175b43c58ac2cdde40521dc7d1dbc607f3dd795d00770206f4fdefb42229e")); - Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256S("628130ae0530f2b24faf1ad2744a83568ac0ffac43e703e30c00d5f137869b84"), {{1,0x80000002UL,3,0x80000004UL}}); - Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32, /*op_desc_id=*/uint256S("4a47b7f497721bf3fc48c69a5d22bc1f3617238649a8ba7cb96fbd92fec84a7e")); - Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/uint256S("a13112753066b5c59473a87c5771b1694a10531944a60e0ab2d7ad66ecb65bcd")); - Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M, /*op_desc_id=*/uint256S("4290f3d017b270be53b91abc56d9d2f23a3ff361d5b1d39550ba011e6cae0da5")); + Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt, /*op_desc_id=*/uint256{"8ef71f7b6ac0918663f6706be469d6109f6922e21f484009d7ab49d77da36e8b"}); + Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt, /*op_desc_id=*/uint256{"5fe175b43c58ac2cdde40521dc7d1dbc607f3dd795d00770206f4fdefb42229e"}); + Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256{"628130ae0530f2b24faf1ad2744a83568ac0ffac43e703e30c00d5f137869b84"}, {{1,0x80000002UL,3,0x80000004UL}}); + Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32, /*op_desc_id=*/uint256{"4a47b7f497721bf3fc48c69a5d22bc1f3617238649a8ba7cb96fbd92fec84a7e"}); + Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/uint256{"a13112753066b5c59473a87c5771b1694a10531944a60e0ab2d7ad66ecb65bcd"}); + Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M, /*op_desc_id=*/uint256{"4290f3d017b270be53b91abc56d9d2f23a3ff361d5b1d39550ba011e6cae0da5"}); CheckUnparsable("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY2))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5))", "wpkh(): Pubkey '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5' is invalid"); // Invalid pubkey CheckUnparsable("pkh(deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Key origin start '[ character expected but not found, got 'd' instead"); // Missing start bracket in key origin CheckUnparsable("pkh([deadbeef]/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef]/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Multiple ']' characters found for a single pubkey"); // Multiple end brackets in key origin // Basic single-key uncompressed - Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, std::nullopt, /*op_desc_id=*/uint256S("33f6bb5d32c04e9d9e5466a8212836743bd5466aa0b8d5331ce8aa0812371ffd")); - Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, std::nullopt, /*op_desc_id=*/uint256S("52306fc1f5d0cb78aacea9d3933092be9252adc27b146f97c16a94d6fcdb652e")); - Check("pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256S("36657e8690d4015032da1a8c1e37b315c3f7ccb010e6ada12967878711962991")); + Check("combo(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)",SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac","76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, std::nullopt, /*op_desc_id=*/uint256{"33f6bb5d32c04e9d9e5466a8212836743bd5466aa0b8d5331ce8aa0812371ffd"}); + Check("pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac"}}, std::nullopt, /*op_desc_id=*/uint256{"52306fc1f5d0cb78aacea9d3933092be9252adc27b146f97c16a94d6fcdb652e"}); + Check("pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256{"36657e8690d4015032da1a8c1e37b315c3f7ccb010e6ada12967878711962991"}); CheckUnparsable("wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "wpkh(): Uncompressed keys are not allowed"); // No uncompressed keys in witness CheckUnparsable("wsh(pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))", "wsh(pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))", "pk(): Uncompressed keys are not allowed"); // No uncompressed keys in witness CheckUnparsable("sh(wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))", "sh(wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))", "wpkh(): Uncompressed keys are not allowed"); // No uncompressed keys in witness @@ -474,16 +474,16 @@ BOOST_AUTO_TEST_CASE(descriptor_test) Check("tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", "tr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5,{pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5),{pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd),pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5)}})", XONLY_KEYS | SIGNABLE | MISSING_PRIVKEYS, {{"51201497ae16f30dacb88523ed9301bff17773b609e8a90518a3f96ea328a47d1500"}}, OutputType::BECH32M); // Versions with BIP32 derivations - Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt, /*op_desc_id=*/uint256S("7f127f7861594e3ede449eb47a7cc623c753acc0b0f0fc03fbb2dac636c20d6f")); - Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, /*op_desc_id=*/uint256S("0e54cf04f2bb8d607e2241d611d169c6f7d78f0ab1f15a80642192a19fbdb7cc"), {{0}}); - Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256S("35a5cf511e941a35b9cb0cf515d3ef887aa4246db87d6af463265a386ad856fe"), {{0xFFFFFFFFUL,0}}); + Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt, /*op_desc_id=*/uint256{"7f127f7861594e3ede449eb47a7cc623c753acc0b0f0fc03fbb2dac636c20d6f"}); + Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, /*op_desc_id=*/uint256{"0e54cf04f2bb8d607e2241d611d169c6f7d78f0ab1f15a80642192a19fbdb7cc"}, {{0}}); + Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, /*op_desc_id=*/uint256{"35a5cf511e941a35b9cb0cf515d3ef887aa4246db87d6af463265a386ad856fe"}, {{0xFFFFFFFFUL,0}}); Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, /*op_desc_id=*/std::nullopt, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}}); Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/std::nullopt, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}}); Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, /*op_desc_id=*/std::nullopt, {{0}, {1}}); Check("tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", XONLY_KEYS | RANGE, {{"512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12"}, {"512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11"}, {"512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25"}}, OutputType::BECH32M, /*op_desc_id=*/std::nullopt, {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}}); // Mixed xpubs and const pubkeys - Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32, /*op_desc_id=*/uint256S("88af8e5951779aa054dfe1071ef0f7266ba1c5558487bfd8525c95010fc0aba2"),{{0},{}}); + Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32, /*op_desc_id=*/uint256{"88af8e5951779aa054dfe1071ef0f7266ba1c5558487bfd8525c95010fc0aba2"},{{0},{}}); // Mixed range xpubs and const pubkeys Check("multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", RANGE | MIXED_PUBKEYS, {{"512102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e0762103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ec2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121035d30b6c66dc1e036c45369da8287518cf7e0d6ed1e2b905171c605708f14ca032103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"}}, std::nullopt, /*op_desc_id=*/std::nullopt,{{2},{1},{0},{}}); @@ -493,14 +493,14 @@ BOOST_AUTO_TEST_CASE(descriptor_test) Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, /*op_desc_id=*/std::nullopt, {{10, 20, 0xFFFFFFFFUL, 0}}); // Multisig constructions - Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt, /*op_desc_id=*/uint256S("b147e25eb4a9d3da4e86ed8e970d817563ae2cb9c71a756b11cfdeb4dc11b70c")); - Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt, /*op_desc_id=*/uint256S("62b59d1e32a62176ef7a17538f3b80c7d1afc53e5644eb753525bdb5d556486c")); + Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt, /*op_desc_id=*/uint256{"b147e25eb4a9d3da4e86ed8e970d817563ae2cb9c71a756b11cfdeb4dc11b70c"}); + Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt, /*op_desc_id=*/uint256{"62b59d1e32a62176ef7a17538f3b80c7d1afc53e5644eb753525bdb5d556486c"}); Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt); Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, /*op_desc_id=*/std::nullopt, {{0x8000006FUL,222},{0}}); Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, /*op_desc_id=*/std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}}); Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, /*op_desc_id=*/std::nullopt, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}}); Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/std::nullopt); - Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M, /*op_desc_id=*/uint256S("af482b44c10b737b678e1091584818372e169e2dc5219e2877fabe1b83ae467b")); + Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M, /*op_desc_id=*/uint256{"af482b44c10b737b678e1091584818372e169e2dc5219e2877fabe1b83ae467b"}); Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,multi_a(1,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,multi_a(1,669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,multi_a(1,669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"5120eb5bd3894327d75093891cc3a62506df7d58ec137fcd104cdd285d67816074f3"}}, OutputType::BECH32M); CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: Multiple ']' characters found for a single pubkey"); // Double key origin descriptor @@ -513,8 +513,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test) CheckUnparsable("multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(3,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be larger than the number of keys; threshold is 3 but only 2 keys specified"); // Threshold larger than number of keys CheckUnparsable("multi(3,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f)", "multi(3,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8)", "Cannot have 4 pubkeys in bare multisig; only at most 3 pubkeys"); // Threshold larger than number of keys CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "P2SH script is too large, 581 bytes is larger than 520 bytes"); // Cannot have more than 15 keys in a P2SH multisig, or we exceed maximum push size - Check("wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))","wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", "wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", SIGNABLE, {{"0020376bd8344b8b6ebe504ff85ef743eaa1aa9272178223bcb6887e9378efb341ac"}}, OutputType::BECH32, /*op_desc_id=*/uint256S("2bb9d418ebdc3a75c465383985881527f3e5d6e520fb3efb152d4191b80e8412")); // In P2WSH we can have up to 20 keys - Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))","sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", "sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", SIGNABLE, {{"a914c2c9c510e9d7f92fd6131e94803a8d34a8ef675e87"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/uint256S("69c3f3153ed2527d12cf78e53e719233fdb7fa6ca9f8a10059ce47d34b49c4cb")); // Even if it's wrapped into P2SH + Check("wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))","wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", "wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd))", SIGNABLE, {{"0020376bd8344b8b6ebe504ff85ef743eaa1aa9272178223bcb6887e9378efb341ac"}}, OutputType::BECH32, /*op_desc_id=*/uint256{"2bb9d418ebdc3a75c465383985881527f3e5d6e520fb3efb152d4191b80e8412"}); // In P2WSH we can have up to 20 keys + Check("sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))","sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", "sh(wsh(multi(20,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232,02bc2feaa536991d269aae46abb8f3772a5b3ad592314945e51543e7da84c4af6e,0318bf32e5217c1eb771a6d5ce1cd39395dff7ff665704f175c9a5451d95a2f2ca,02c681a6243f16208c2004bb81f5a8a67edfdd3e3711534eadeec3dcf0b010c759,0249fdd6b69768b8d84b4893f8ff84b36835c50183de20fcae8f366a45290d01fd)))", SIGNABLE, {{"a914c2c9c510e9d7f92fd6131e94803a8d34a8ef675e87"}}, OutputType::P2SH_SEGWIT, /*op_desc_id=*/uint256{"69c3f3153ed2527d12cf78e53e719233fdb7fa6ca9f8a10059ce47d34b49c4cb"}); // Even if it's wrapped into P2SH // Check for invalid nesting of structures CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "A function is needed within P2SH"); // P2SH needs a script, not a key CheckUnparsable("sh(combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "Can only have combo() at top level"); // Old must be top level @@ -525,8 +525,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test) CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH // Checksums - Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#hgmsckna", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, /*op_desc_id=*/uint256S("9339b7bfbe8cfd9d0d55819778ef77f52e5786e85b4c83be8a0d5b976e033f4c"), {{0x8000006FUL,222},{0}}); - Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, /*op_desc_id=*/uint256S("9339b7bfbe8cfd9d0d55819778ef77f52e5786e85b4c83be8a0d5b976e033f4c"), {{0x8000006FUL,222},{0}}); + Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#hgmsckna", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, /*op_desc_id=*/uint256{"9339b7bfbe8cfd9d0d55819778ef77f52e5786e85b4c83be8a0d5b976e033f4c"}, {{0x8000006FUL,222},{0}}); + Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, /*op_desc_id=*/uint256{"9339b7bfbe8cfd9d0d55819778ef77f52e5786e85b4c83be8a0d5b976e033f4c"}, {{0x8000006FUL,222},{0}}); CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#", "Expected 8 character checksum, not 0 characters"); // Empty checksum CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5tq", "Expected 8 character checksum, not 9 characters"); // Too long checksum CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxf", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5", "Expected 8 character checksum, not 7 characters"); // Too short checksum @@ -546,7 +546,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test) RANGE | HARDENED | XONLY_KEYS, {{"51205172af752f057d543ce8e4a6f8dcf15548ec6be44041bfa93b72e191cfc8c1ee"}, {"51201b66f20b86f700c945ecb9ad9b0ad1662b73084e2bfea48bee02126350b8a5b1"}, {"512063e70f66d815218abcc2306aa930aaca07c5cde73b75127eb27b5e8c16b58a25"}}, OutputType::BECH32M, - /*op_desc_id=*/uint256S("458f0e7f4075a81c990c6be6d5b985027ac8b7f7cef8311696d95b7b49658c7d"), + /*op_desc_id=*/uint256{"458f0e7f4075a81c990c6be6d5b985027ac8b7f7cef8311696d95b7b49658c7d"}, {{0x80000056, 0x80000001, 0x80000000, 1, 0}, {0x80000056, 0x80000001, 0x80000000, 1, 1}, {0x80000056, 0x80000001, 0x80000000, 1, 2}}); Check( @@ -556,7 +556,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test) SIGNABLE | XONLY_KEYS, {{"5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd"}}, OutputType::BECH32M, - /*op_desc_id=*/uint256S("5ba3f7d83cee4795df00e0eaa5070a3e164283c5fc6e8586fd710eaa7a4168ec")); + /*op_desc_id=*/uint256{"5ba3f7d83cee4795df00e0eaa5070a3e164283c5fc6e8586fd710eaa7a4168ec"}); CheckUnparsable( "", @@ -607,31 +607,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)))", DEFAULT, {{"0020acf425291b98a1d7e0d4690139442abc289175be32ef1f75945e339924246d73"}}, OutputType::BECH32, /*op_desc_id=*/uint256S("0634b326edc66f9e2660562564d7a8fcca55f91dc4555ce0a51883cc72e0fa41"), {{},{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, /*op_desc_id=*/uint256{"0634b326edc66f9e2660562564d7a8fcca55f91dc4555ce0a51883cc72e0fa41"}, {{},{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, /*op_desc_id=*/uint256S("3cfcad33bc25579d70b23ce634d317be00a4e5400e758e37c215bdc17b31bfb8"), {{},{0}}); + 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, /*op_desc_id=*/uint256{"3cfcad33bc25579d70b23ce634d317be00a4e5400e758e37c215bdc17b31bfb8"}, {{},{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, /*op_desc_id=*/std::nullopt, {{},{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, /*op_desc_id=*/uint256S("f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"), {{},{0}}, /*spender_nlocktime=*/1000, /*spender_nsequence=*/1); + 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, /*op_desc_id=*/uint256{"f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"}, {{},{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, /*op_desc_id=*/uint256S("f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"), {{},{0}}, /*spender_nlocktime=*/999, /*spender_nsequence=*/2); + 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, /*op_desc_id=*/uint256{"f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"}, {{},{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, /*op_desc_id=*/uint256S("f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"), {{},{0}}, /*spender_nlocktime=*/1000, /*spender_nsequence=*/2); + 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, /*op_desc_id=*/uint256{"f5c14a15b45d2af1b8ec69acfd3cf4790f069705d1b079efb0b8193fed181f64"}, {{},{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, /*op_desc_id=*/uint256S("1fed6fbd0e408eb4bddfefa075289dc7061e7a3240c84f6ba5b9f294d96a21f4"), {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {}); + 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, /*op_desc_id=*/uint256{"1fed6fbd0e408eb4bddfefa075289dc7061e7a3240c84f6ba5b9f294d96a21f4"}, {{}}, /*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, /*op_desc_id=*/uint256S("1fed6fbd0e408eb4bddfefa075289dc7061e7a3240c84f6ba5b9f294d96a21f4"), {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("ff9aa1829c90d26e73301383f549e1497b7d6325"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + 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, /*op_desc_id=*/uint256{"1fed6fbd0e408eb4bddfefa075289dc7061e7a3240c84f6ba5b9f294d96a21f4"}, {{}}, /*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, /*op_desc_id=*/uint256S("a1809a65ba5ca2f09a06c114d4881eed95d1b62f38743cf126cf71b2dd411374"), {{}}, /*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, /*op_desc_id=*/uint256S("a1809a65ba5ca2f09a06c114d4881eed95d1b62f38743cf126cf71b2dd411374"), {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("7426ba0604c3f8682c7016b44673f85c5bd9da2fa6c1080810cf53ae320c9863"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + 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, /*op_desc_id=*/uint256{"a1809a65ba5ca2f09a06c114d4881eed95d1b62f38743cf126cf71b2dd411374"}, {{}}, /*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, /*op_desc_id=*/uint256{"a1809a65ba5ca2f09a06c114d4881eed95d1b62f38743cf126cf71b2dd411374"}, {{}}, /*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, /*op_desc_id=*/uint256S("d7bdbc680503a585925eec72d11fc99396f51855d0a03fce53c90bed4c2e319f"), {{}}, /*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, /*op_desc_id=*/uint256S("d7bdbc680503a585925eec72d11fc99396f51855d0a03fce53c90bed4c2e319f"), {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("292e2df59e3a22109200beed0cdc84b12e66793e"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + 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, /*op_desc_id=*/uint256{"d7bdbc680503a585925eec72d11fc99396f51855d0a03fce53c90bed4c2e319f"}, {{}}, /*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, /*op_desc_id=*/uint256{"d7bdbc680503a585925eec72d11fc99396f51855d0a03fce53c90bed4c2e319f"}, {{}}, /*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, /*op_desc_id=*/uint256S("8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"), {{}}, /*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, /*op_desc_id=*/uint256S("8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"), {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); + 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, /*op_desc_id=*/uint256{"8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"}, {{}}, /*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, /*op_desc_id=*/uint256{"8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{ParseHex("ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"), ParseHex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")}}); // Can have a Miniscript expression under tr() if it's alone. Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(L1NKM8dVA1h52mwDrmk1YreTWkAZZTu2vmKLpmLEbFRqGQYjHeEV),s:pk(Kz3iCBy3HNGP5CZWDsAMmnCMFNwqdDohudVN9fvkrN7tAkzKNtM7),adv:older(42)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),s:pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766),adv:older(42)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),s:pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766),adv:older(42)))", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"512033982eebe204dc66508e4b19cfc31b5ffc6e1bfcbf6e5597dfc2521a52270795"}}, OutputType::BECH32M); // Can have a pkh() expression alone as tr() script path (because pkh() is valid Miniscript). diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 8a54cc656d..dbec2bc858 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -124,7 +124,7 @@ public: explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider) : AddrMan(netgroupman, /*deterministic=*/true, GetCheckRatio()) { - WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); + WITH_LOCK(m_impl->cs, m_impl->insecure_rand.Reseed(ConsumeUInt256(fuzzed_data_provider))); } /** diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp index ffc5ba518f..daa6e24404 100644 --- a/src/test/fuzz/bech32.cpp +++ b/src/test/fuzz/bech32.cpp @@ -29,8 +29,9 @@ FUZZ_TARGET(bech32) std::vector<unsigned char> input; ConvertBits<8, 5, true>([&](unsigned char c) { input.push_back(c); }, buffer.begin(), buffer.end()); - if (input.size() + 3 + 6 <= 90) { - // If it's possible to encode input in Bech32(m) without exceeding the 90-character limit: + // Input data part + 3 characters for the HRP and separator (bc1) + the checksum characters + if (input.size() + 3 + bech32::CHECKSUM_SIZE <= bech32::CharLimit::BECH32) { + // If it's possible to encode input in Bech32(m) without exceeding the bech32-character limit: for (auto encoding : {bech32::Encoding::BECH32, bech32::Encoding::BECH32M}) { const std::string encoded = bech32::Encode(encoding, "bc", input); assert(!encoded.empty()); diff --git a/src/test/fuzz/bip324.cpp b/src/test/fuzz/bip324.cpp index 8210e75cee..9892e7a81c 100644 --- a/src/test/fuzz/bip324.cpp +++ b/src/test/fuzz/bip324.cpp @@ -4,11 +4,11 @@ #include <bip324.h> #include <chainparams.h> +#include <random.h> #include <span.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <test/util/xoroshiro128plusplus.h> #include <cstdint> #include <vector> @@ -56,7 +56,7 @@ FUZZ_TARGET(bip324_cipher_roundtrip, .init=Initialize) // (potentially buggy) edge cases triggered by specific values of contents/AAD, so we can avoid // reading the actual data for those from the fuzzer input (which would need large amounts of // data). - XoRoShiRo128PlusPlus rng(provider.ConsumeIntegral<uint64_t>()); + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); // Compare session IDs and garbage terminators. assert(initiator.GetSessionID() == responder.GetSessionID()); @@ -79,10 +79,8 @@ FUZZ_TARGET(bip324_cipher_roundtrip, .init=Initialize) unsigned length_bits = 2 * ((mode >> 5) & 7); unsigned length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << length_bits) - 1); // Generate aad and content. - std::vector<std::byte> aad(aad_length); - for (auto& val : aad) val = std::byte{(uint8_t)rng()}; - std::vector<std::byte> contents(length); - for (auto& val : contents) val = std::byte{(uint8_t)rng()}; + auto aad = rng.randbytes<std::byte>(aad_length); + auto contents = rng.randbytes<std::byte>(length); // Pick sides. auto& sender{from_init ? initiator : responder}; diff --git a/src/test/fuzz/bitset.cpp b/src/test/fuzz/bitset.cpp index 7684337729..ce6be0499c 100644 --- a/src/test/fuzz/bitset.cpp +++ b/src/test/fuzz/bitset.cpp @@ -2,9 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <random.h> #include <span.h> #include <test/fuzz/util.h> -#include <test/util/xoroshiro128plusplus.h> #include <util/bitset.h> #include <bitset> @@ -29,7 +29,7 @@ void TestType(FuzzBufferType buffer) * bitsets and their simulations do not matter for the purpose of detecting edge cases, thus * these are taken from a deterministically-seeded RNG instead. To provide some level of * variation however, pick the seed based on the buffer size and size of the chosen bitset. */ - XoRoShiRo128PlusPlus rng(buffer.size() + 0x10000 * S::Size()); + InsecureRandomContext rng(buffer.size() + 0x10000 * S::Size()); using Sim = std::bitset<S::Size()>; // Up to 4 real BitSets (initially 2). @@ -124,7 +124,7 @@ void TestType(FuzzBufferType buffer) sim[dest].reset(); real[dest] = S{}; for (unsigned i = 0; i < S::Size(); ++i) { - if (rng() & 1) { + if (rng.randbool()) { sim[dest][i] = true; real[dest].Set(i); } @@ -132,9 +132,9 @@ void TestType(FuzzBufferType buffer) break; } else if (dest < sim.size() && command-- == 0) { /* Assign initializer list. */ - unsigned r1 = rng() % S::Size(); - unsigned r2 = rng() % S::Size(); - unsigned r3 = rng() % S::Size(); + unsigned r1 = rng.randrange(S::Size()); + unsigned r2 = rng.randrange(S::Size()); + unsigned r3 = rng.randrange(S::Size()); compare_fn(dest); sim[dest].reset(); real[dest] = {r1, r2, r3}; @@ -166,8 +166,8 @@ void TestType(FuzzBufferType buffer) break; } else if (sim.size() < 4 && command-- == 0) { /* Construct with initializer list. */ - unsigned r1 = rng() % S::Size(); - unsigned r2 = rng() % S::Size(); + unsigned r1 = rng.randrange(S::Size()); + unsigned r2 = rng.randrange(S::Size()); sim.emplace_back(); sim.back().set(r1); sim.back().set(r2); diff --git a/src/test/fuzz/block_header.cpp b/src/test/fuzz/block_header.cpp index c73270dcb3..2e446b16eb 100644 --- a/src/test/fuzz/block_header.cpp +++ b/src/test/fuzz/block_header.cpp @@ -23,7 +23,7 @@ FUZZ_TARGET(block_header) } { const uint256 hash = block_header->GetHash(); - static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + constexpr uint256 u256_max{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; assert(hash != u256_max); assert(block_header->GetBlockTime() == block_header->nTime); assert(block_header->IsNull() == (block_header->nBits == 0)); diff --git a/src/test/fuzz/block_index.cpp b/src/test/fuzz/block_index.cpp new file mode 100644 index 0000000000..eef8c2efc8 --- /dev/null +++ b/src/test/fuzz/block_index.cpp @@ -0,0 +1,133 @@ +// 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 <chain.h> +#include <chainparams.h> +#include <node/blockstorage.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <test/util/setup_common.h> +#include <txdb.h> +#include <validation.h> + +namespace { + +const BasicTestingSetup* g_setup; + +// Hardcoded block hash and nBits to make sure the blocks we store pass the pow check. +uint256 g_block_hash; + +bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b) +{ + return a.nBlocks == b.nBlocks && + a.nSize == b.nSize && + a.nUndoSize == b.nUndoSize && + a.nHeightFirst == b.nHeightFirst && + a.nHeightLast == b.nHeightLast && + a.nTimeFirst == b.nTimeFirst && + a.nTimeLast == b.nTimeLast; +} + +CBlockHeader ConsumeBlockHeader(FuzzedDataProvider& provider) +{ + CBlockHeader header; + header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>(); + header.hashPrevBlock = g_block_hash; + header.hashMerkleRoot = g_block_hash; + header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>(); + header.nBits = Params().GenesisBlock().nBits; + header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>(); + return header; +} + +} // namespace + +void init_block_index() +{ + static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN); + g_setup = testing_setup.get(); + g_block_hash = Params().GenesisBlock().GetHash(); +} + +FUZZ_TARGET(block_index, .init = init_block_index) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + auto block_index = kernel::BlockTreeDB(DBParams{ + .path = "", // Memory only. + .cache_bytes = 1 << 20, // 1MB. + .memory_only = true, + }); + + // Generate a number of block files to be stored in the index. + int files_count = fuzzed_data_provider.ConsumeIntegralInRange(1, 100); + std::vector<std::unique_ptr<CBlockFileInfo>> files; + files.reserve(files_count); + std::vector<std::pair<int, const CBlockFileInfo*>> files_info; + files_info.reserve(files_count); + for (int i = 0; i < files_count; i++) { + if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) { + files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info))); + files_info.emplace_back(i, files.back().get()); + } else { + return; + } + } + + // Generate a number of block headers to be stored in the index. + int blocks_count = fuzzed_data_provider.ConsumeIntegralInRange(files_count * 10, files_count * 100); + std::vector<std::unique_ptr<CBlockIndex>> blocks; + blocks.reserve(blocks_count); + std::vector<const CBlockIndex*> blocks_info; + blocks_info.reserve(blocks_count); + for (int i = 0; i < blocks_count; i++) { + CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)}; + blocks.push_back(std::make_unique<CBlockIndex>(std::move(header))); + blocks.back()->phashBlock = &g_block_hash; + blocks_info.push_back(blocks.back().get()); + } + + // Store these files and blocks in the block index. It should not fail. + assert(block_index.WriteBatchSync(files_info, files_count - 1, blocks_info)); + + // We should be able to read every block file info we stored. Its value should correspond to + // what we stored above. + CBlockFileInfo info; + for (const auto& [n, file_info]: files_info) { + assert(block_index.ReadBlockFileInfo(n, info)); + assert(info == *file_info); + } + + // We should be able to read the last block file number. Its value should be consistent. + int last_block_file; + assert(block_index.ReadLastBlockFile(last_block_file)); + assert(last_block_file == files_count - 1); + + // We should be able to flip and read the reindexing flag. + bool reindexing; + block_index.WriteReindexing(true); + block_index.ReadReindexing(reindexing); + assert(reindexing); + block_index.WriteReindexing(false); + block_index.ReadReindexing(reindexing); + assert(!reindexing); + + // We should be able to set and read the value of any random flag. + const std::string flag_name = fuzzed_data_provider.ConsumeRandomLengthString(100); + bool flag_value; + block_index.WriteFlag(flag_name, true); + block_index.ReadFlag(flag_name, flag_value); + assert(flag_value); + block_index.WriteFlag(flag_name, false); + block_index.ReadFlag(flag_name, flag_value); + assert(!flag_value); + + // We should be able to load everything we've previously stored. Note to assert on the + // return value we need to make sure all blocks pass the pow check. + const auto params{Params().GetConsensus()}; + const auto inserter = [&](const uint256&) { + return blocks.back().get(); + }; + WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt))); +} diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp new file mode 100644 index 0000000000..2dfdfbb41d --- /dev/null +++ b/src/test/fuzz/cluster_linearize.cpp @@ -0,0 +1,957 @@ +// Copyright (c) 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 <cluster_linearize.h> +#include <serialize.h> +#include <streams.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/util/cluster_linearize.h> +#include <util/bitset.h> +#include <util/feefrac.h> + +#include <algorithm> +#include <stdint.h> +#include <vector> +#include <utility> + +using namespace cluster_linearize; + +namespace { + +/** A simple finder class for candidate sets. + * + * This class matches SearchCandidateFinder in interface and behavior, though with fewer + * optimizations. + */ +template<typename SetType> +class SimpleCandidateFinder +{ + /** Internal dependency graph. */ + const DepGraph<SetType>& m_depgraph; + /** Which transaction are left to include. */ + SetType m_todo; + +public: + /** Construct an SimpleCandidateFinder for a given graph. */ + SimpleCandidateFinder(const DepGraph<SetType>& depgraph LIFETIMEBOUND) noexcept : + m_depgraph(depgraph), m_todo{SetType::Fill(depgraph.TxCount())} {} + + /** Remove a set of transactions from the set of to-be-linearized ones. */ + void MarkDone(SetType select) noexcept { m_todo -= select; } + + /** Determine whether unlinearized transactions remain. */ + bool AllDone() const noexcept { return m_todo.None(); } + + /** Find a candidate set using at most max_iterations iterations, and the number of iterations + * actually performed. If that number is less than max_iterations, then the result is optimal. + * + * Complexity: O(N * M), where M is the number of connected topological subsets of the cluster. + * That number is bounded by M <= 2^(N-1). + */ + std::pair<SetInfo<SetType>, uint64_t> FindCandidateSet(uint64_t max_iterations) const noexcept + { + uint64_t iterations_left = max_iterations; + // Queue of work units. Each consists of: + // - inc: set of transactions definitely included + // - und: set of transactions that can be added to inc still + std::vector<std::pair<SetType, SetType>> queue; + // Initially we have just one queue element, with the entire graph in und. + queue.emplace_back(SetType{}, m_todo); + // Best solution so far. + SetInfo best(m_depgraph, m_todo); + // Process the queue. + while (!queue.empty() && iterations_left) { + --iterations_left; + // Pop top element of the queue. + auto [inc, und] = queue.back(); + queue.pop_back(); + // Look for a transaction to consider adding/removing. + bool inc_none = inc.None(); + for (auto split : und) { + // If inc is empty, consider any split transaction. Otherwise only consider + // transactions that share ancestry with inc so far (which means only connected + // sets will be considered). + if (inc_none || inc.Overlaps(m_depgraph.Ancestors(split))) { + // Add a queue entry with split included. + SetInfo new_inc(m_depgraph, inc | (m_todo & m_depgraph.Ancestors(split))); + queue.emplace_back(new_inc.transactions, und - new_inc.transactions); + // Add a queue entry with split excluded. + queue.emplace_back(inc, und - m_depgraph.Descendants(split)); + // Update statistics to account for the candidate new_inc. + if (new_inc.feerate > best.feerate) best = new_inc; + break; + } + } + } + return {std::move(best), max_iterations - iterations_left}; + } +}; + +/** A very simple finder class for optimal candidate sets, which tries every subset. + * + * It is even simpler than SimpleCandidateFinder, and is primarily included here to test the + * correctness of SimpleCandidateFinder, which is then used to test the correctness of + * SearchCandidateFinder. + */ +template<typename SetType> +class ExhaustiveCandidateFinder +{ + /** Internal dependency graph. */ + const DepGraph<SetType>& m_depgraph; + /** Which transaction are left to include. */ + SetType m_todo; + +public: + /** Construct an ExhaustiveCandidateFinder for a given graph. */ + ExhaustiveCandidateFinder(const DepGraph<SetType>& depgraph LIFETIMEBOUND) noexcept : + m_depgraph(depgraph), m_todo{SetType::Fill(depgraph.TxCount())} {} + + /** Remove a set of transactions from the set of to-be-linearized ones. */ + void MarkDone(SetType select) noexcept { m_todo -= select; } + + /** Determine whether unlinearized transactions remain. */ + bool AllDone() const noexcept { return m_todo.None(); } + + /** Find the optimal remaining candidate set. + * + * Complexity: O(N * 2^N). + */ + SetInfo<SetType> FindCandidateSet() const noexcept + { + // Best solution so far. + SetInfo<SetType> best{m_todo, m_depgraph.FeeRate(m_todo)}; + // The number of combinations to try. + uint64_t limit = (uint64_t{1} << m_todo.Count()) - 1; + // Try the transitive closure of every non-empty subset of m_todo. + for (uint64_t x = 1; x < limit; ++x) { + // If bit number b is set in x, then the remaining ancestors of the b'th remaining + // transaction in m_todo are included. + SetType txn; + auto x_shifted{x}; + for (auto i : m_todo) { + if (x_shifted & 1) txn |= m_depgraph.Ancestors(i); + x_shifted >>= 1; + } + SetInfo cur(m_depgraph, txn & m_todo); + if (cur.feerate > best.feerate) best = cur; + } + return best; + } +}; + +/** A simple linearization algorithm. + * + * This matches Linearize() in interface and behavior, though with fewer optimizations, lacking + * the ability to pass in an existing linearization, and using just SimpleCandidateFinder rather + * than AncestorCandidateFinder and SearchCandidateFinder. + */ +template<typename SetType> +std::pair<std::vector<ClusterIndex>, bool> SimpleLinearize(const DepGraph<SetType>& depgraph, uint64_t max_iterations) +{ + std::vector<ClusterIndex> linearization; + SimpleCandidateFinder finder(depgraph); + SetType todo = SetType::Fill(depgraph.TxCount()); + bool optimal = true; + while (todo.Any()) { + auto [candidate, iterations_done] = finder.FindCandidateSet(max_iterations); + if (iterations_done == max_iterations) optimal = false; + depgraph.AppendTopo(linearization, candidate.transactions); + todo -= candidate.transactions; + finder.MarkDone(candidate.transactions); + max_iterations -= iterations_done; + } + return {std::move(linearization), optimal}; +} + +/** Given a dependency graph, and a todo set, read a topological subset of todo from reader. */ +template<typename SetType> +SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader) +{ + uint64_t mask{0}; + try { + reader >> VARINT(mask); + } catch(const std::ios_base::failure&) {} + SetType ret; + for (auto i : todo) { + if (!ret[i]) { + if (mask & 1) ret |= depgraph.Ancestors(i); + mask >>= 1; + } + } + return ret & todo; +} + +/** Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */ +template<typename BS> +std::vector<ClusterIndex> ReadLinearization(const DepGraph<BS>& depgraph, SpanReader& reader) +{ + std::vector<ClusterIndex> linearization; + TestBitSet todo = TestBitSet::Fill(depgraph.TxCount()); + // In every iteration one topologically-valid transaction is appended to linearization. + while (todo.Any()) { + // Compute the set of transactions with no not-yet-included ancestors. + TestBitSet potential_next; + for (auto j : todo) { + if ((depgraph.Ancestors(j) & todo) == TestBitSet::Singleton(j)) { + potential_next.Set(j); + } + } + // There must always be one (otherwise there is a cycle in the graph). + assert(potential_next.Any()); + // Read a number from reader, and interpret it as index into potential_next. + uint64_t idx{0}; + try { + reader >> VARINT(idx); + } catch (const std::ios_base::failure&) {} + idx %= potential_next.Count(); + // Find out which transaction that corresponds to. + for (auto j : potential_next) { + if (idx == 0) { + // When found, add it to linearization and remove it from todo. + linearization.push_back(j); + assert(todo[j]); + todo.Reset(j); + break; + } + --idx; + } + } + return linearization; +} + +} // namespace + +FUZZ_TARGET(clusterlin_add_dependency) +{ + // Verify that computing a DepGraph from a cluster, or building it step by step using AddDependency + // have the same effect. + + // Construct a cluster of a certain length, with no dependencies. + FuzzedDataProvider provider(buffer.data(), buffer.size()); + auto num_tx = provider.ConsumeIntegralInRange<ClusterIndex>(2, 32); + Cluster<TestBitSet> cluster(num_tx, std::pair{FeeFrac{0, 1}, TestBitSet{}}); + // Construct the corresponding DepGraph object (also no dependencies). + DepGraph depgraph(cluster); + SanityCheck(depgraph); + // Read (parent, child) pairs, and add them to the cluster and depgraph. + LIMITED_WHILE(provider.remaining_bytes() > 0, TestBitSet::Size() * TestBitSet::Size()) { + auto parent = provider.ConsumeIntegralInRange<ClusterIndex>(0, num_tx - 1); + auto child = provider.ConsumeIntegralInRange<ClusterIndex>(0, num_tx - 2); + child += (child >= parent); + cluster[child].second.Set(parent); + depgraph.AddDependency(parent, child); + assert(depgraph.Ancestors(child)[parent]); + assert(depgraph.Descendants(parent)[child]); + } + // Sanity check the result. + SanityCheck(depgraph); + // Verify that the resulting DepGraph matches one recomputed from the cluster. + assert(DepGraph(cluster) == depgraph); +} + +FUZZ_TARGET(clusterlin_cluster_serialization) +{ + // Verify that any graph of transactions has its ancestry correctly computed by DepGraph, and + // if it is a DAG, that it can be serialized as a DepGraph in a way that roundtrips. This + // guarantees that any acyclic cluster has a corresponding DepGraph serialization. + + FuzzedDataProvider provider(buffer.data(), buffer.size()); + + // Construct a cluster in a naive way (using a FuzzedDataProvider-based serialization). + Cluster<TestBitSet> cluster; + auto num_tx = provider.ConsumeIntegralInRange<ClusterIndex>(1, 32); + cluster.resize(num_tx); + for (ClusterIndex i = 0; i < num_tx; ++i) { + cluster[i].first.size = provider.ConsumeIntegralInRange<int32_t>(1, 0x3fffff); + cluster[i].first.fee = provider.ConsumeIntegralInRange<int64_t>(-0x8000000000000, 0x7ffffffffffff); + for (ClusterIndex j = 0; j < num_tx; ++j) { + if (i == j) continue; + if (provider.ConsumeBool()) cluster[i].second.Set(j); + } + } + + // Construct dependency graph, and verify it matches the cluster (which includes a round-trip + // check for the serialization). + DepGraph depgraph(cluster); + VerifyDepGraphFromCluster(cluster, depgraph); +} + +FUZZ_TARGET(clusterlin_depgraph_serialization) +{ + // Verify that any deserialized depgraph is acyclic and roundtrips to an identical depgraph. + + // Construct a graph by deserializing. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + SanityCheck(depgraph); + + // Verify the graph is a DAG. + assert(IsAcyclic(depgraph)); +} + +FUZZ_TARGET(clusterlin_components) +{ + // Verify the behavior of DepGraphs's FindConnectedComponent and IsConnected functions. + + // Construct a depgraph. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + TestBitSet todo = TestBitSet::Fill(depgraph.TxCount()); + while (todo.Any()) { + // Find a connected component inside todo. + auto component = depgraph.FindConnectedComponent(todo); + + // The component must be a subset of todo and non-empty. + assert(component.IsSubsetOf(todo)); + assert(component.Any()); + + // If todo is the entire graph, and the entire graph is connected, then the component must + // be the entire graph. + if (todo == TestBitSet::Fill(depgraph.TxCount())) { + assert((component == todo) == depgraph.IsConnected()); + } + + // If subset is connected, then component must match subset. + assert((component == todo) == depgraph.IsConnected(todo)); + + // The component cannot have any ancestors or descendants outside of component but in todo. + for (auto i : component) { + assert((depgraph.Ancestors(i) & todo).IsSubsetOf(component)); + assert((depgraph.Descendants(i) & todo).IsSubsetOf(component)); + } + + // Starting from any component element, we must be able to reach every element. + for (auto i : component) { + // Start with just i as reachable. + TestBitSet reachable = TestBitSet::Singleton(i); + // Add in-todo descendants and ancestors to reachable until it does not change anymore. + while (true) { + TestBitSet new_reachable = reachable; + for (auto j : new_reachable) { + new_reachable |= depgraph.Ancestors(j) & todo; + new_reachable |= depgraph.Descendants(j) & todo; + } + if (new_reachable == reachable) break; + reachable = new_reachable; + } + // Verify that the result is the entire component. + assert(component == reachable); + } + + // Construct an arbitrary subset of todo. + uint64_t subset_bits{0}; + try { + reader >> VARINT(subset_bits); + } catch (const std::ios_base::failure&) {} + TestBitSet subset; + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + if (todo[i]) { + if (subset_bits & 1) subset.Set(i); + subset_bits >>= 1; + } + } + // Which must be non-empty. + if (subset.None()) subset = TestBitSet::Singleton(todo.First()); + // Remove it from todo. + todo -= subset; + } + + // No components can be found in an empty subset. + assert(depgraph.FindConnectedComponent(todo).None()); +} + +FUZZ_TARGET(clusterlin_chunking) +{ + // Verify the correctness of the ChunkLinearization function. + + // Construct a graph by deserializing. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + // Read a valid linearization for depgraph. + auto linearization = ReadLinearization(depgraph, reader); + + // Invoke the chunking function. + auto chunking = ChunkLinearization(depgraph, linearization); + + // Verify that chunk feerates are monotonically non-increasing. + for (size_t i = 1; i < chunking.size(); ++i) { + assert(!(chunking[i] >> chunking[i - 1])); + } + + // Naively recompute the chunks (each is the highest-feerate prefix of what remains). + auto todo = TestBitSet::Fill(depgraph.TxCount()); + for (const auto& chunk_feerate : chunking) { + assert(todo.Any()); + SetInfo<TestBitSet> accumulator, best; + for (ClusterIndex idx : linearization) { + if (todo[idx]) { + accumulator |= SetInfo(depgraph, idx); + if (best.feerate.IsEmpty() || accumulator.feerate >> best.feerate) { + best = accumulator; + } + } + } + assert(chunk_feerate == best.feerate); + assert(best.transactions.IsSubsetOf(todo)); + todo -= best.transactions; + } + assert(todo.None()); +} + +FUZZ_TARGET(clusterlin_ancestor_finder) +{ + // Verify that AncestorCandidateFinder works as expected. + + // Retrieve a depgraph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + AncestorCandidateFinder anc_finder(depgraph); + auto todo = TestBitSet::Fill(depgraph.TxCount()); + while (todo.Any()) { + // Call the ancestor finder's FindCandidateSet for what remains of the graph. + assert(!anc_finder.AllDone()); + auto best_anc = anc_finder.FindCandidateSet(); + // Sanity check the result. + assert(best_anc.transactions.Any()); + assert(best_anc.transactions.IsSubsetOf(todo)); + assert(depgraph.FeeRate(best_anc.transactions) == best_anc.feerate); + assert(depgraph.IsConnected(best_anc.transactions)); + // Check that it is topologically valid. + for (auto i : best_anc.transactions) { + assert((depgraph.Ancestors(i) & todo).IsSubsetOf(best_anc.transactions)); + } + + // Compute all remaining ancestor sets. + std::optional<SetInfo<TestBitSet>> real_best_anc; + for (auto i : todo) { + SetInfo info(depgraph, todo & depgraph.Ancestors(i)); + if (!real_best_anc.has_value() || info.feerate > real_best_anc->feerate) { + real_best_anc = info; + } + } + // The set returned by anc_finder must equal the real best ancestor sets. + assert(real_best_anc.has_value()); + assert(*real_best_anc == best_anc); + + // Find a topologically valid subset of transactions to remove from the graph. + auto del_set = ReadTopologicalSet(depgraph, todo, reader); + // If we did not find anything, use best_anc itself, because we should remove something. + if (del_set.None()) del_set = best_anc.transactions; + todo -= del_set; + anc_finder.MarkDone(del_set); + } + assert(anc_finder.AllDone()); +} + +static constexpr auto MAX_SIMPLE_ITERATIONS = 300000; + +FUZZ_TARGET(clusterlin_search_finder) +{ + // Verify that SearchCandidateFinder works as expected by sanity checking the results + // and comparing with the results from SimpleCandidateFinder, ExhaustiveCandidateFinder, and + // AncestorCandidateFinder. + + // Retrieve an RNG seed and a depgraph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + uint64_t rng_seed{0}; + try { + reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed; + } catch (const std::ios_base::failure&) {} + + // Instantiate ALL the candidate finders. + SearchCandidateFinder src_finder(depgraph, rng_seed); + SimpleCandidateFinder smp_finder(depgraph); + ExhaustiveCandidateFinder exh_finder(depgraph); + AncestorCandidateFinder anc_finder(depgraph); + + auto todo = TestBitSet::Fill(depgraph.TxCount()); + while (todo.Any()) { + assert(!src_finder.AllDone()); + assert(!smp_finder.AllDone()); + assert(!exh_finder.AllDone()); + assert(!anc_finder.AllDone()); + + // For each iteration, read an iteration count limit from the fuzz input. + uint64_t max_iterations = 1; + try { + reader >> VARINT(max_iterations); + } catch (const std::ios_base::failure&) {} + max_iterations &= 0xfffff; + + // Read an initial subset from the fuzz input. + SetInfo init_best(depgraph, ReadTopologicalSet(depgraph, todo, reader)); + + // Call the search finder's FindCandidateSet for what remains of the graph. + auto [found, iterations_done] = src_finder.FindCandidateSet(max_iterations, init_best); + + // Sanity check the result. + assert(iterations_done <= max_iterations); + assert(found.transactions.Any()); + assert(found.transactions.IsSubsetOf(todo)); + assert(depgraph.FeeRate(found.transactions) == found.feerate); + if (!init_best.feerate.IsEmpty()) assert(found.feerate >= init_best.feerate); + // Check that it is topologically valid. + for (auto i : found.transactions) { + assert(found.transactions.IsSupersetOf(depgraph.Ancestors(i) & todo)); + } + + // At most 2^N-1 iterations can be required: the number of non-empty subsets a graph with N + // transactions has. + assert(iterations_done <= ((uint64_t{1} << todo.Count()) - 1)); + + // Perform quality checks only if SearchCandidateFinder claims an optimal result. + if (iterations_done < max_iterations) { + // Optimal sets are always connected. + assert(depgraph.IsConnected(found.transactions)); + + // Compare with SimpleCandidateFinder. + auto [simple, simple_iters] = smp_finder.FindCandidateSet(MAX_SIMPLE_ITERATIONS); + assert(found.feerate >= simple.feerate); + if (simple_iters < MAX_SIMPLE_ITERATIONS) { + assert(found.feerate == simple.feerate); + } + + // Compare with AncestorCandidateFinder; + auto anc = anc_finder.FindCandidateSet(); + assert(found.feerate >= anc.feerate); + + // Compare with ExhaustiveCandidateFinder. This quickly gets computationally expensive + // for large clusters (O(2^n)), so only do it for sufficiently small ones. + if (todo.Count() <= 12) { + auto exhaustive = exh_finder.FindCandidateSet(); + assert(exhaustive.feerate == found.feerate); + // Also compare ExhaustiveCandidateFinder with SimpleCandidateFinder (this is + // primarily a test for SimpleCandidateFinder's correctness). + assert(exhaustive.feerate >= simple.feerate); + if (simple_iters < MAX_SIMPLE_ITERATIONS) { + assert(exhaustive.feerate == simple.feerate); + } + } + } + + // Find a topologically valid subset of transactions to remove from the graph. + auto del_set = ReadTopologicalSet(depgraph, todo, reader); + // If we did not find anything, use found itself, because we should remove something. + if (del_set.None()) del_set = found.transactions; + todo -= del_set; + src_finder.MarkDone(del_set); + smp_finder.MarkDone(del_set); + exh_finder.MarkDone(del_set); + anc_finder.MarkDone(del_set); + } + + assert(src_finder.AllDone()); + assert(smp_finder.AllDone()); + assert(exh_finder.AllDone()); + assert(anc_finder.AllDone()); +} + +FUZZ_TARGET(clusterlin_linearization_chunking) +{ + // Verify the behavior of LinearizationChunking. + + // Retrieve a depgraph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + // Retrieve a topologically-valid subset of depgraph. + auto todo = TestBitSet::Fill(depgraph.TxCount()); + auto subset = SetInfo(depgraph, ReadTopologicalSet(depgraph, todo, reader)); + + // Retrieve a valid linearization for depgraph. + auto linearization = ReadLinearization(depgraph, reader); + + // Construct a LinearizationChunking object, initially for the whole linearization. + LinearizationChunking chunking(depgraph, linearization); + + // Incrementally remove transactions from the chunking object, and check various properties at + // every step. + while (todo.Any()) { + assert(chunking.NumChunksLeft() > 0); + + // Construct linearization with just todo. + std::vector<ClusterIndex> linearization_left; + for (auto i : linearization) { + if (todo[i]) linearization_left.push_back(i); + } + + // Compute the chunking for linearization_left. + auto chunking_left = ChunkLinearization(depgraph, linearization_left); + + // Verify that it matches the feerates of the chunks of chunking. + assert(chunking.NumChunksLeft() == chunking_left.size()); + for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + assert(chunking.GetChunk(i).feerate == chunking_left[i]); + } + + // Check consistency of chunking. + TestBitSet combined; + for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + const auto& chunk_info = chunking.GetChunk(i); + // Chunks must be non-empty. + assert(chunk_info.transactions.Any()); + // Chunk feerates must be monotonically non-increasing. + if (i > 0) assert(!(chunk_info.feerate >> chunking.GetChunk(i - 1).feerate)); + // Chunks must be a subset of what is left of the linearization. + assert(chunk_info.transactions.IsSubsetOf(todo)); + // Chunks' claimed feerates must match their transactions' aggregate feerate. + assert(depgraph.FeeRate(chunk_info.transactions) == chunk_info.feerate); + // Chunks must be the highest-feerate remaining prefix. + SetInfo<TestBitSet> accumulator, best; + for (auto j : linearization) { + if (todo[j] && !combined[j]) { + accumulator |= SetInfo(depgraph, j); + if (best.feerate.IsEmpty() || accumulator.feerate > best.feerate) { + best = accumulator; + } + } + } + assert(best.transactions == chunk_info.transactions); + assert(best.feerate == chunk_info.feerate); + // Chunks cannot overlap. + assert(!chunk_info.transactions.Overlaps(combined)); + combined |= chunk_info.transactions; + // Chunks must be topological. + for (auto idx : chunk_info.transactions) { + assert((depgraph.Ancestors(idx) & todo).IsSubsetOf(combined)); + } + } + assert(combined == todo); + + // Verify the expected properties of LinearizationChunking::IntersectPrefixes: + auto intersect = chunking.IntersectPrefixes(subset); + // - Intersecting again doesn't change the result. + assert(chunking.IntersectPrefixes(intersect) == intersect); + // - The intersection is topological. + TestBitSet intersect_anc; + for (auto idx : intersect.transactions) { + intersect_anc |= (depgraph.Ancestors(idx) & todo); + } + assert(intersect.transactions == intersect_anc); + // - The claimed intersection feerate matches its transactions. + assert(intersect.feerate == depgraph.FeeRate(intersect.transactions)); + // - The intersection may only be empty if its input is empty. + assert(intersect.transactions.Any() == subset.transactions.Any()); + // - The intersection feerate must be as high as the input. + assert(intersect.feerate >= subset.feerate); + // - No non-empty intersection between the intersection and a prefix of the chunks of the + // remainder of the linearization may be better than the intersection. + TestBitSet prefix; + for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + prefix |= chunking.GetChunk(i).transactions; + auto reintersect = SetInfo(depgraph, prefix & intersect.transactions); + if (!reintersect.feerate.IsEmpty()) { + assert(reintersect.feerate <= intersect.feerate); + } + } + + // Find a subset to remove from linearization. + auto done = ReadTopologicalSet(depgraph, todo, reader); + if (done.None()) { + // We need to remove a non-empty subset, so fall back to the unlinearized ancestors of + // the first transaction in todo if done is empty. + done = depgraph.Ancestors(todo.First()) & todo; + } + todo -= done; + chunking.MarkDone(done); + subset = SetInfo(depgraph, subset.transactions - done); + } + + assert(chunking.NumChunksLeft() == 0); +} + +FUZZ_TARGET(clusterlin_linearize) +{ + // Verify the behavior of Linearize(). + + // Retrieve an RNG seed, an iteration count, and a depgraph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + uint64_t rng_seed{0}; + uint64_t iter_count{0}; + try { + reader >> VARINT(iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed; + } catch (const std::ios_base::failure&) {} + + // Optionally construct an old linearization for it. + std::vector<ClusterIndex> old_linearization; + { + uint8_t have_old_linearization{0}; + try { + reader >> have_old_linearization; + } catch(const std::ios_base::failure&) {} + if (have_old_linearization & 1) { + old_linearization = ReadLinearization(depgraph, reader); + SanityCheck(depgraph, old_linearization); + } + } + + // Invoke Linearize(). + iter_count &= 0x7ffff; + auto [linearization, optimal] = Linearize(depgraph, iter_count, rng_seed, old_linearization); + SanityCheck(depgraph, linearization); + auto chunking = ChunkLinearization(depgraph, linearization); + + // Linearization must always be as good as the old one, if provided. + if (!old_linearization.empty()) { + auto old_chunking = ChunkLinearization(depgraph, old_linearization); + auto cmp = CompareChunks(chunking, old_chunking); + assert(cmp >= 0); + } + + // If the iteration count is sufficiently high, an optimal linearization must be found. + // Each linearization step can use up to 2^k iterations, with steps k=1..n. That sum is + // 2 * (2^n - 1) + const uint64_t n = depgraph.TxCount(); + if (n <= 18 && iter_count > 2U * ((uint64_t{1} << n) - 1U)) { + assert(optimal); + } + + // If Linearize claims optimal result, run quality tests. + if (optimal) { + // It must be as good as SimpleLinearize. + auto [simple_linearization, simple_optimal] = SimpleLinearize(depgraph, MAX_SIMPLE_ITERATIONS); + SanityCheck(depgraph, simple_linearization); + auto simple_chunking = ChunkLinearization(depgraph, simple_linearization); + auto cmp = CompareChunks(chunking, simple_chunking); + assert(cmp >= 0); + // If SimpleLinearize finds the optimal result too, they must be equal (if not, + // SimpleLinearize is broken). + if (simple_optimal) assert(cmp == 0); + + // Only for very small clusters, test every topologically-valid permutation. + if (depgraph.TxCount() <= 7) { + std::vector<ClusterIndex> perm_linearization(depgraph.TxCount()); + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) perm_linearization[i] = i; + // Iterate over all valid permutations. + do { + // Determine whether perm_linearization is topological. + TestBitSet perm_done; + bool perm_is_topo{true}; + for (auto i : perm_linearization) { + perm_done.Set(i); + if (!depgraph.Ancestors(i).IsSubsetOf(perm_done)) { + perm_is_topo = false; + break; + } + } + // If so, verify that the obtained linearization is as good as the permutation. + if (perm_is_topo) { + auto perm_chunking = ChunkLinearization(depgraph, perm_linearization); + auto cmp = CompareChunks(chunking, perm_chunking); + assert(cmp >= 0); + } + } while(std::next_permutation(perm_linearization.begin(), perm_linearization.end())); + } + } +} + +FUZZ_TARGET(clusterlin_postlinearize) +{ + // Verify expected properties of PostLinearize() on arbitrary linearizations. + + // Retrieve a depgraph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + // Retrieve a linearization from the fuzz input. + std::vector<ClusterIndex> linearization; + linearization = ReadLinearization(depgraph, reader); + SanityCheck(depgraph, linearization); + + // Produce a post-processed version. + auto post_linearization = linearization; + PostLinearize(depgraph, post_linearization); + SanityCheck(depgraph, post_linearization); + + // Compare diagrams: post-linearization cannot worsen anywhere. + auto chunking = ChunkLinearization(depgraph, linearization); + auto post_chunking = ChunkLinearization(depgraph, post_linearization); + auto cmp = CompareChunks(post_chunking, chunking); + assert(cmp >= 0); + + // Run again, things can keep improving (and never get worse) + auto post_post_linearization = post_linearization; + PostLinearize(depgraph, post_post_linearization); + SanityCheck(depgraph, post_post_linearization); + auto post_post_chunking = ChunkLinearization(depgraph, post_post_linearization); + cmp = CompareChunks(post_post_chunking, post_chunking); + assert(cmp >= 0); + + // The chunks that come out of postlinearizing are always connected. + LinearizationChunking linchunking(depgraph, post_linearization); + while (linchunking.NumChunksLeft()) { + assert(depgraph.IsConnected(linchunking.GetChunk(0).transactions)); + linchunking.MarkDone(linchunking.GetChunk(0).transactions); + } +} + +FUZZ_TARGET(clusterlin_postlinearize_tree) +{ + // Verify expected properties of PostLinearize() on linearizations of graphs that form either + // an upright or reverse tree structure. + + // Construct a direction, RNG seed, and an arbitrary graph from the fuzz input. + SpanReader reader(buffer); + uint64_t rng_seed{0}; + DepGraph<TestBitSet> depgraph_gen; + uint8_t direction{0}; + try { + reader >> direction >> rng_seed >> Using<DepGraphFormatter>(depgraph_gen); + } catch (const std::ios_base::failure&) {} + + // Now construct a new graph, copying the nodes, but leaving only the first parent (even + // direction) or the first child (odd direction). + DepGraph<TestBitSet> depgraph_tree; + for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + depgraph_tree.AddTransaction(depgraph_gen.FeeRate(i)); + } + if (direction & 1) { + for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + auto children = depgraph_gen.Descendants(i) - TestBitSet::Singleton(i); + // Remove descendants that are children of other descendants. + for (auto j : children) { + if (!children[j]) continue; + children -= depgraph_gen.Descendants(j); + children.Set(j); + } + if (children.Any()) depgraph_tree.AddDependency(i, children.First()); + } + } else { + for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + auto parents = depgraph_gen.Ancestors(i) - TestBitSet::Singleton(i); + // Remove ancestors that are parents of other ancestors. + for (auto j : parents) { + if (!parents[j]) continue; + parents -= depgraph_gen.Ancestors(j); + parents.Set(j); + } + if (parents.Any()) depgraph_tree.AddDependency(parents.First(), i); + } + } + + // Retrieve a linearization from the fuzz input. + std::vector<ClusterIndex> linearization; + linearization = ReadLinearization(depgraph_tree, reader); + SanityCheck(depgraph_tree, linearization); + + // Produce a postlinearized version. + auto post_linearization = linearization; + PostLinearize(depgraph_tree, post_linearization); + SanityCheck(depgraph_tree, post_linearization); + + // Compare diagrams. + auto chunking = ChunkLinearization(depgraph_tree, linearization); + auto post_chunking = ChunkLinearization(depgraph_tree, post_linearization); + auto cmp = CompareChunks(post_chunking, chunking); + assert(cmp >= 0); + + // Verify that post-linearizing again does not change the diagram. The result must be identical + // as post_linearization ought to be optimal already with a tree-structured graph. + auto post_post_linearization = post_linearization; + PostLinearize(depgraph_tree, post_linearization); + SanityCheck(depgraph_tree, post_linearization); + auto post_post_chunking = ChunkLinearization(depgraph_tree, post_post_linearization); + auto cmp_post = CompareChunks(post_post_chunking, post_chunking); + assert(cmp_post == 0); + + // Try to find an even better linearization directly. This must not change the diagram for the + // same reason. + auto [opt_linearization, _optimal] = Linearize(depgraph_tree, 100000, rng_seed, post_linearization); + auto opt_chunking = ChunkLinearization(depgraph_tree, opt_linearization); + auto cmp_opt = CompareChunks(opt_chunking, post_chunking); + assert(cmp_opt == 0); +} + +FUZZ_TARGET(clusterlin_postlinearize_moved_leaf) +{ + // Verify that taking an existing linearization, and moving a leaf to the back, potentially + // increasing its fee, and then post-linearizing, results in something as good as the + // original. This guarantees that in an RBF that replaces a transaction with one of the same + // size but higher fee, applying the "remove conflicts, append new transaction, postlinearize" + // process will never worsen linearization quality. + + // Construct an arbitrary graph and a fee from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + int32_t fee_inc{0}; + try { + uint64_t fee_inc_code; + reader >> Using<DepGraphFormatter>(depgraph) >> VARINT(fee_inc_code); + fee_inc = fee_inc_code & 0x3ffff; + } catch (const std::ios_base::failure&) {} + if (depgraph.TxCount() == 0) return; + + // Retrieve two linearizations from the fuzz input. + auto lin = ReadLinearization(depgraph, reader); + auto lin_leaf = ReadLinearization(depgraph, reader); + + // Construct a linearization identical to lin, but with the tail end of lin_leaf moved to the + // back. + std::vector<ClusterIndex> lin_moved; + for (auto i : lin) { + if (i != lin_leaf.back()) lin_moved.push_back(i); + } + lin_moved.push_back(lin_leaf.back()); + + // Postlinearize lin_moved. + PostLinearize(depgraph, lin_moved); + SanityCheck(depgraph, lin_moved); + + // Compare diagrams (applying the fee delta after computing the old one). + auto old_chunking = ChunkLinearization(depgraph, lin); + depgraph.FeeRate(lin_leaf.back()).fee += fee_inc; + auto new_chunking = ChunkLinearization(depgraph, lin_moved); + auto cmp = CompareChunks(new_chunking, old_chunking); + assert(cmp >= 0); +} + +FUZZ_TARGET(clusterlin_merge) +{ + // Construct an arbitrary graph from the fuzz input. + SpanReader reader(buffer); + DepGraph<TestBitSet> depgraph; + try { + reader >> Using<DepGraphFormatter>(depgraph); + } catch (const std::ios_base::failure&) {} + + // Retrieve two linearizations from the fuzz input. + auto lin1 = ReadLinearization(depgraph, reader); + auto lin2 = ReadLinearization(depgraph, reader); + + // Merge the two. + auto lin_merged = MergeLinearizations(depgraph, lin1, lin2); + + // Compute chunkings and compare. + auto chunking1 = ChunkLinearization(depgraph, lin1); + auto chunking2 = ChunkLinearization(depgraph, lin2); + auto chunking_merged = ChunkLinearization(depgraph, lin_merged); + auto cmp1 = CompareChunks(chunking_merged, chunking1); + assert(cmp1 >= 0); + auto cmp2 = CompareChunks(chunking_merged, chunking2); + assert(cmp2 >= 0); +} diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 8f3e357a84..368c69819a 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -27,7 +27,6 @@ #include <vector> namespace { -const TestingSetup* g_setup; const Coin EMPTY_COIN{}; bool operator==(const Coin& a, const Coin& b) @@ -39,8 +38,7 @@ bool operator==(const Coin& a, const Coin& b) void initialize_coins_view() { - static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); - g_setup = testing_setup.get(); + static const auto testing_setup = MakeNoLogFileContext<>(); } FUZZ_TARGET(coins_view, .init = initialize_coins_view) @@ -122,12 +120,15 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view) random_mutable_transaction = *opt_mutable_transaction; }, [&] { + CoinsCachePair sentinel{}; + sentinel.second.SelfRef(sentinel); + size_t usage{0}; CCoinsMapMemoryResource resource; CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource}; LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000) { CCoinsCacheEntry coins_cache_entry; - coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>(); + const auto flags{fuzzed_data_provider.ConsumeIntegral<uint8_t>()}; if (fuzzed_data_provider.ConsumeBool()) { coins_cache_entry.coin = random_coin; } else { @@ -138,11 +139,14 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view) } coins_cache_entry.coin = *opt_coin; } - coins_map.emplace(random_out_point, std::move(coins_cache_entry)); + auto it{coins_map.emplace(random_out_point, std::move(coins_cache_entry)).first}; + it->second.AddFlags(flags, *it, sentinel); + usage += it->second.coin.DynamicMemoryUsage(); } bool expected_code_path = false; try { - coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); + auto cursor{CoinsViewCacheCursor(usage, sentinel, coins_map, /*will_erase=*/true)}; + coins_view_cache.BatchWrite(cursor, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); expected_code_path = true; } catch (const std::logic_error& e) { if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { diff --git a/src/test/fuzz/coinscache_sim.cpp b/src/test/fuzz/coinscache_sim.cpp index 648e96b4a0..8e717e96b4 100644 --- a/src/test/fuzz/coinscache_sim.cpp +++ b/src/test/fuzz/coinscache_sim.cpp @@ -172,13 +172,13 @@ public: 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 + bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final { - for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) { - if (it->second.flags & CCoinsCacheEntry::DIRTY) { + for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) { + if (it->second.IsDirty()) { if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) { m_data.erase(it->first); - } else if (erase) { + } else if (cursor.WillErase(*it)) { m_data[it->first] = std::move(it->second.coin); } else { m_data[it->first] = it->second.coin; diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index 50c77bf699..d115a2b7e1 100644 --- a/src/test/fuzz/crypto_chacha20.cpp +++ b/src/test/fuzz/crypto_chacha20.cpp @@ -3,10 +3,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <crypto/chacha20.h> +#include <random.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <test/util/xoroshiro128plusplus.h> #include <array> #include <cstddef> @@ -53,7 +53,7 @@ namespace 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 UseCrypt, seeded InsecureRandomContext output is used as input to Crypt(). If not, Keystream() is used directly, or sequences of 0x00 are encrypted. */ template<bool UseCrypt> @@ -78,25 +78,11 @@ void ChaCha20SplitFuzz(FuzzedDataProvider& provider) data1.resize(total_bytes); data2.resize(total_bytes); - // If using Crypt(), initialize data1 and data2 with the same Xoroshiro128++ based + // If using Crypt(), initialize data1 and data2 with the same InsecureRandomContext 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(UCharCast(data1.data() + bytes), val); - WriteLE64(UCharCast(data2.data() + bytes), val); - bytes += 8; - } - if (bytes < total_bytes) { - std::byte valbytes[8]; - uint64_t val = rng(); - WriteLE64(UCharCast(valbytes), val); - std::copy(valbytes, valbytes + (total_bytes - bytes), data1.data() + bytes); - std::copy(valbytes, valbytes + (total_bytes - bytes), data2.data() + bytes); - } + InsecureRandomContext(provider.ConsumeIntegral<uint64_t>()).fillrand(data1); + std::copy(data1.begin(), data1.end(), data2.begin()); } // Whether UseCrypt is used or not, the two byte arrays must match. diff --git a/src/test/fuzz/crypto_chacha20poly1305.cpp b/src/test/fuzz/crypto_chacha20poly1305.cpp new file mode 100644 index 0000000000..2b39a06094 --- /dev/null +++ b/src/test/fuzz/crypto_chacha20poly1305.cpp @@ -0,0 +1,200 @@ +// 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. + +#include <crypto/chacha20poly1305.h> +#include <random.h> +#include <span.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cstddef> +#include <cstdint> +#include <vector> + +constexpr static inline void crypt_till_rekey(FSChaCha20Poly1305& aead, int rekey_interval, bool encrypt) +{ + for (int i = 0; i < rekey_interval; ++i) { + std::byte dummy_tag[FSChaCha20Poly1305::EXPANSION] = {{}}; + if (encrypt) { + aead.Encrypt(Span{dummy_tag}.first(0), Span{dummy_tag}.first(0), dummy_tag); + } else { + aead.Decrypt(dummy_tag, Span{dummy_tag}.first(0), Span{dummy_tag}.first(0)); + } + } +} + +FUZZ_TARGET(crypto_aeadchacha20poly1305) +{ + FuzzedDataProvider provider{buffer.data(), buffer.size()}; + + auto key = provider.ConsumeBytes<std::byte>(32); + key.resize(32); + AEADChaCha20Poly1305 aead(key); + + // Initialize RNG deterministically, to generate contents and AAD. We assume that there are no + // (potentially buggy) edge cases triggered by specific values of contents/AAD, so we can avoid + // reading the actual data for those from the fuzzer input (which would need large amounts of + // data). + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); + + LIMITED_WHILE(provider.ConsumeBool(), 10000) + { + // Mode: + // - Bit 0: whether to use single-plain Encrypt/Decrypt; otherwise use a split at prefix. + // - Bit 2: whether this ciphertext will be corrupted (making it the last sent one) + // - Bit 3-4: controls the maximum aad length (max 511 bytes) + // - Bit 5-7: controls the maximum content length (max 16383 bytes, for performance reasons) + unsigned mode = provider.ConsumeIntegral<uint8_t>(); + bool use_splits = mode & 1; + bool damage = mode & 4; + unsigned aad_length_bits = 3 * ((mode >> 3) & 3); + unsigned aad_length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << aad_length_bits) - 1); + unsigned length_bits = 2 * ((mode >> 5) & 7); + unsigned length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << length_bits) - 1); + // Generate aad and content. + auto aad = rng.randbytes<std::byte>(aad_length); + auto plain = rng.randbytes<std::byte>(length); + std::vector<std::byte> cipher(length + AEADChaCha20Poly1305::EXPANSION); + // Generate nonce + AEADChaCha20Poly1305::Nonce96 nonce = {(uint32_t)rng(), rng()}; + + if (use_splits && length > 0) { + size_t split_index = provider.ConsumeIntegralInRange<size_t>(1, length); + aead.Encrypt(Span{plain}.first(split_index), Span{plain}.subspan(split_index), aad, nonce, cipher); + } else { + aead.Encrypt(plain, aad, nonce, cipher); + } + + // Test Keystream output + std::vector<std::byte> keystream(length); + aead.Keystream(nonce, keystream); + for (size_t i = 0; i < length; ++i) { + assert((plain[i] ^ keystream[i]) == cipher[i]); + } + + std::vector<std::byte> decrypted_contents(length); + bool ok{false}; + + // damage the key + unsigned key_position = provider.ConsumeIntegralInRange<unsigned>(0, 31); + std::byte damage_val{(uint8_t)(1U << (key_position & 7))}; + std::vector<std::byte> bad_key = key; + bad_key[key_position] ^= damage_val; + + AEADChaCha20Poly1305 bad_aead(bad_key); + ok = bad_aead.Decrypt(cipher, aad, nonce, decrypted_contents); + assert(!ok); + + // Optionally damage 1 bit in either the cipher (corresponding to a change in transit) + // or the aad (to make sure that decryption will fail if the AAD mismatches). + if (damage) { + unsigned damage_bit = provider.ConsumeIntegralInRange<unsigned>(0, (cipher.size() + aad.size()) * 8U - 1U); + unsigned damage_pos = damage_bit >> 3; + std::byte damage_val{(uint8_t)(1U << (damage_bit & 7))}; + if (damage_pos >= cipher.size()) { + aad[damage_pos - cipher.size()] ^= damage_val; + } else { + cipher[damage_pos] ^= damage_val; + } + } + + if (use_splits && length > 0) { + size_t split_index = provider.ConsumeIntegralInRange<size_t>(1, length); + ok = aead.Decrypt(cipher, aad, nonce, Span{decrypted_contents}.first(split_index), Span{decrypted_contents}.subspan(split_index)); + } else { + ok = aead.Decrypt(cipher, aad, nonce, decrypted_contents); + } + + // Decryption *must* fail if the packet was damaged, and succeed if it wasn't. + assert(!ok == damage); + if (!ok) break; + assert(decrypted_contents == plain); + } +} + +FUZZ_TARGET(crypto_fschacha20poly1305) +{ + FuzzedDataProvider provider{buffer.data(), buffer.size()}; + + uint32_t rekey_interval = provider.ConsumeIntegralInRange<size_t>(32, 512); + auto key = provider.ConsumeBytes<std::byte>(32); + key.resize(32); + FSChaCha20Poly1305 enc_aead(key, rekey_interval); + FSChaCha20Poly1305 dec_aead(key, rekey_interval); + + // Initialize RNG deterministically, to generate contents and AAD. We assume that there are no + // (potentially buggy) edge cases triggered by specific values of contents/AAD, so we can avoid + // reading the actual data for those from the fuzzer input (which would need large amounts of + // data). + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); + + LIMITED_WHILE(provider.ConsumeBool(), 10000) + { + // Mode: + // - Bit 0: whether to use single-plain Encrypt/Decrypt; otherwise use a split at prefix. + // - Bit 2: whether this ciphertext will be corrupted (making it the last sent one) + // - Bit 3-4: controls the maximum aad length (max 511 bytes) + // - Bit 5-7: controls the maximum content length (max 16383 bytes, for performance reasons) + unsigned mode = provider.ConsumeIntegral<uint8_t>(); + bool use_splits = mode & 1; + bool damage = mode & 4; + unsigned aad_length_bits = 3 * ((mode >> 3) & 3); + unsigned aad_length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << aad_length_bits) - 1); + unsigned length_bits = 2 * ((mode >> 5) & 7); + unsigned length = provider.ConsumeIntegralInRange<unsigned>(0, (1 << length_bits) - 1); + // Generate aad and content. + auto aad = rng.randbytes<std::byte>(aad_length); + auto plain = rng.randbytes<std::byte>(length); + std::vector<std::byte> cipher(length + FSChaCha20Poly1305::EXPANSION); + + crypt_till_rekey(enc_aead, rekey_interval, true); + if (use_splits && length > 0) { + size_t split_index = provider.ConsumeIntegralInRange<size_t>(1, length); + enc_aead.Encrypt(Span{plain}.first(split_index), Span{plain}.subspan(split_index), aad, cipher); + } else { + enc_aead.Encrypt(plain, aad, cipher); + } + + std::vector<std::byte> decrypted_contents(length); + bool ok{false}; + + // damage the key + unsigned key_position = provider.ConsumeIntegralInRange<unsigned>(0, 31); + std::byte damage_val{(uint8_t)(1U << (key_position & 7))}; + std::vector<std::byte> bad_key = key; + bad_key[key_position] ^= damage_val; + + FSChaCha20Poly1305 bad_fs_aead(bad_key, rekey_interval); + crypt_till_rekey(bad_fs_aead, rekey_interval, false); + ok = bad_fs_aead.Decrypt(cipher, aad, decrypted_contents); + assert(!ok); + + // Optionally damage 1 bit in either the cipher (corresponding to a change in transit) + // or the aad (to make sure that decryption will fail if the AAD mismatches). + if (damage) { + unsigned damage_bit = provider.ConsumeIntegralInRange<unsigned>(0, (cipher.size() + aad.size()) * 8U - 1U); + unsigned damage_pos = damage_bit >> 3; + std::byte damage_val{(uint8_t)(1U << (damage_bit & 7))}; + if (damage_pos >= cipher.size()) { + aad[damage_pos - cipher.size()] ^= damage_val; + } else { + cipher[damage_pos] ^= damage_val; + } + } + + crypt_till_rekey(dec_aead, rekey_interval, false); + if (use_splits && length > 0) { + size_t split_index = provider.ConsumeIntegralInRange<size_t>(1, length); + ok = dec_aead.Decrypt(cipher, aad, Span{decrypted_contents}.first(split_index), Span{decrypted_contents}.subspan(split_index)); + } else { + ok = dec_aead.Decrypt(cipher, aad, decrypted_contents); + } + + // Decryption *must* fail if the packet was damaged, and succeed if it wasn't. + assert(!ok == damage); + if (!ok) break; + assert(decrypted_contents == plain); + } +} diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index b9a5560ffb..6a3f4d6dfe 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -72,6 +72,14 @@ FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse) // out strings which could correspond to a descriptor containing a too large derivation path. if (HasDeepDerivPath(buffer)) return; + // Some fragments can take a virtually unlimited number of sub-fragments (thresh, multi_a) but + // may perform quadratic operations on them. Limit the number of sub-fragments per fragment. + if (HasTooManySubFrag(buffer)) return; + + // The script building logic performs quadratic copies in the number of nested wrappers. Limit + // the number of nested wrappers per fragment. + if (HasTooManyWrappers(buffer)) return; + const std::string mocked_descriptor{buffer.begin(), buffer.end()}; if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) { FlatSigningProvider signing_provider; @@ -83,8 +91,10 @@ FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse) FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse) { - // See comment above for rationale. + // See comments above for rationales. if (HasDeepDerivPath(buffer)) return; + if (HasTooManySubFrag(buffer)) return; + if (HasTooManyWrappers(buffer)) return; const std::string descriptor(buffer.begin(), buffer.end()); FlatSigningProvider signing_provider; diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index c1c9945a04..96283a3e15 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -6,6 +6,7 @@ #include <netaddress.h> #include <netbase.h> +#include <test/util/random.h> #include <test/util/setup_common.h> #include <util/check.h> #include <util/fs.h> @@ -72,8 +73,8 @@ auto& FuzzTargets() void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts) { - const auto it_ins{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped after clang-16 */ {std::move(target), std::move(opts)})}; - Assert(it_ins.second); + const auto [it, ins]{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped after Apple-Clang-16 ? */ {std::move(target), std::move(opts)})}; + Assert(ins); } static std::string_view g_fuzz_target; @@ -101,6 +102,12 @@ void ResetCoverageCounters() {} void initialize() { + // By default, make the RNG deterministic with a fixed seed. This will affect all + // randomness during the fuzz test, except: + // - GetStrongRandBytes(), which is used for the creation of private key material. + // - Creating a BasicTestingSetup or derived class will switch to a random seed. + SeedRandomForTest(SeedRand::ZEROS); + // Terminate immediately if a fuzzing harness ever tries to create a socket. // Individual tests can override this by pointing CreateSock to a mocked alternative. CreateSock = [](int, int, int) -> std::unique_ptr<Sock> { std::terminate(); }; diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp index f67b820d11..ebe30c3c1a 100644 --- a/src/test/fuzz/hex.cpp +++ b/src/test/fuzz/hex.cpp @@ -10,6 +10,7 @@ #include <uint256.h> #include <univalue.h> #include <util/strencodings.h> +#include <util/transaction_identifier.h> #include <cassert> #include <cstdint> @@ -27,8 +28,11 @@ FUZZ_TARGET(hex) assert(ToLower(random_hex_string) == hex_data); } (void)IsHexNumber(random_hex_string); - uint256 result; - (void)ParseHashStr(random_hex_string, result); + if (uint256::FromHex(random_hex_string)) { + assert(random_hex_string.length() == 64); + assert(Txid::FromHex(random_hex_string)); + assert(Wtxid::FromHex(random_hex_string)); + } (void)uint256S(random_hex_string); try { (void)HexToPubKey(random_hex_string); diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 8f1d7b6d45..02c6796d11 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -78,8 +78,8 @@ FUZZ_TARGET(integer, .init = initialize_integer) } else { (void)CompressAmount(u64); } - static const uint256 u256_min(uint256S("0000000000000000000000000000000000000000000000000000000000000000")); - static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + constexpr uint256 u256_min{"0000000000000000000000000000000000000000000000000000000000000000"}; + constexpr uint256 u256_max{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; const std::vector<uint256> v256{u256, u256_min, u256_max}; (void)ComputeMerkleRoot(v256); (void)DecompressAmount(u64); diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp index 4468f358d9..62b49106cd 100644 --- a/src/test/fuzz/kitchen_sink.cpp +++ b/src/test/fuzz/kitchen_sink.cpp @@ -23,7 +23,7 @@ using node::TransactionError; namespace { constexpr TransactionError ALL_TRANSACTION_ERROR[] = { TransactionError::MISSING_INPUTS, - TransactionError::ALREADY_IN_CHAIN, + TransactionError::ALREADY_IN_UTXO_SET, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::MAX_FEE_EXCEEDED, diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp index 3a1663364f..51de4d0166 100644 --- a/src/test/fuzz/mini_miner.cpp +++ b/src/test/fuzz/mini_miner.cpp @@ -188,9 +188,9 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner) auto mock_template_txids = mini_miner.GetMockTemplateTxids(); // MiniMiner doesn't add a coinbase tx. assert(mock_template_txids.count(blocktemplate->block.vtx[0]->GetHash()) == 0); - mock_template_txids.emplace(blocktemplate->block.vtx[0]->GetHash()); - assert(mock_template_txids.size() <= blocktemplate->block.vtx.size()); - assert(mock_template_txids.size() >= blocktemplate->block.vtx.size()); + auto [iter, new_entry] = mock_template_txids.emplace(blocktemplate->block.vtx[0]->GetHash()); + assert(new_entry); + assert(mock_template_txids.size() == blocktemplate->block.vtx.size()); for (const auto& tx : blocktemplate->block.vtx) { assert(mock_template_txids.count(tx->GetHash())); diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index 7e71af7c44..1f9ed9a064 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -47,9 +47,9 @@ struct TestData { void Init() { unsigned char keydata[32] = {1}; // All our signatures sign (and are required to sign) this constant message. - auto const MESSAGE_HASH{uint256S("f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065")}; + constexpr uint256 MESSAGE_HASH{"0000000000000000f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"}; // We don't pass additional randomness when creating a schnorr signature. - auto const EMPTY_AUX{uint256S("")}; + const auto EMPTY_AUX{uint256::ZERO}; for (size_t i = 0; i < 256; i++) { keydata[31] = i; diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp index dd34c465ed..e74bcb962f 100644 --- a/src/test/fuzz/muhash.cpp +++ b/src/test/fuzz/muhash.cpp @@ -20,7 +20,7 @@ FUZZ_TARGET(muhash) muhash.Insert(data); muhash.Insert(data2); - const std::string initial_state_hash{"dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8"}; + constexpr uint256 initial_state_hash{"dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8"}; uint256 out; uint256 out2; CallOneOf( @@ -57,14 +57,14 @@ FUZZ_TARGET(muhash) #endif muhash.Finalize(out); - out2 = uint256S(initial_state_hash); + out2 = initial_state_hash; }, [&] { // Test that removing all added elements brings the object back to it's initial state muhash.Remove(data); muhash.Remove(data2); muhash.Finalize(out); - out2 = uint256S(initial_state_hash); + out2 = initial_state_hash; }); assert(out == out2); } diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index e8b1480c5b..4cec96274e 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -33,6 +33,11 @@ FUZZ_TARGET(net, .init = initialize_net) SetMockTime(ConsumeTime(fuzzed_data_provider)); CNode node{ConsumeNode(fuzzed_data_provider)}; node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>()); + if (const auto service_opt = + ConsumeDeserializable<CService>(fuzzed_data_provider, ConsumeDeserializationParams<CNetAddr::SerParams>(fuzzed_data_provider))) + { + node.SetAddrLocal(*service_opt); + } LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { CallOneOf( fuzzed_data_provider, @@ -53,13 +58,6 @@ FUZZ_TARGET(net, .init = initialize_net) } }, [&] { - const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider, ConsumeDeserializationParams<CNetAddr::SerParams>(fuzzed_data_provider)); - if (!service_opt) { - return; - } - node.SetAddrLocal(*service_opt); - }, - [&] { const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); bool complete; node.ReceiveMsgBytes(b, complete); diff --git a/src/test/fuzz/p2p_handshake.cpp b/src/test/fuzz/p2p_handshake.cpp new file mode 100644 index 0000000000..217655ab70 --- /dev/null +++ b/src/test/fuzz/p2p_handshake.cpp @@ -0,0 +1,107 @@ +// Copyright (c) 2020-present 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 <addrman.h> +#include <consensus/consensus.h> +#include <net.h> +#include <net_processing.h> +#include <node/warnings.h> +#include <protocol.h> +#include <script/script.h> +#include <sync.h> +#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 <util/time.h> +#include <validationinterface.h> + +#include <ios> +#include <string> +#include <utility> +#include <vector> + +namespace { +const TestingSetup* g_setup; + +void initialize() +{ + static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>( + /*chain_type=*/ChainType::REGTEST); + g_setup = testing_setup.get(); +} +} // namespace + +FUZZ_TARGET(p2p_handshake, .init = ::initialize) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*g_setup->m_node.connman); + auto& chainman = static_cast<TestChainstateManager&>(*g_setup->m_node.chainman); + SetMockTime(1610000000); // any time to successfully reset ibd + chainman.ResetIbd(); + + node::Warnings warnings{}; + NetGroupManager netgroupman{{}}; + AddrMan addrman{netgroupman, /*deterministic=*/true, 0}; + auto peerman = PeerManager::make(connman, addrman, + /*banman=*/nullptr, chainman, + *g_setup->m_node.mempool, warnings, + PeerManager::Options{ + .reconcile_txs = true, + .deterministic_rng = true, + }); + connman.SetMsgProc(peerman.get()); + + LOCK(NetEventsInterface::g_msgproc_mutex); + + std::vector<CNode*> peers; + const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3); + for (int i = 0; i < num_peers_to_add; ++i) { + peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release()); + connman.AddTestNode(*peers.back()); + peerman->InitializeNode( + *peers.back(), + static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>())); + } + + LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) + { + CNode& connection = *PickValue(fuzzed_data_provider, peers); + if (connection.fDisconnect || connection.fSuccessfullyConnected) { + // Skip if the the connection was disconnected or if the version + // handshake was already completed. + continue; + } + + SetMockTime(GetTime() + + fuzzed_data_provider.ConsumeIntegralInRange<int64_t>( + -std::chrono::seconds{10min}.count(), // Allow mocktime to go backwards slightly + std::chrono::seconds{TIMEOUT_INTERVAL}.count())); + + CSerializedNetMsg net_msg; + net_msg.m_type = PickValue(fuzzed_data_provider, ALL_NET_MESSAGE_TYPES); + net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider, MAX_PROTOCOL_MESSAGE_LENGTH); + + connman.FlushSendBuffer(connection); + (void)connman.ReceiveMsgFrom(connection, std::move(net_msg)); + + bool more_work{true}; + while (more_work) { + connection.fPauseSend = false; + + try { + more_work = connman.ProcessMessagesOnce(connection); + } catch (const std::ios_base::failure&) { + } + peerman->SendMessages(&connection); + } + } + + g_setup->m_node.connman->StopNodes(); +} diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index 767238d103..93f77b6e5b 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -10,7 +10,6 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> -#include <test/util/xoroshiro128plusplus.h> #include <util/chaintype.h> #include <cassert> @@ -104,7 +103,7 @@ FUZZ_TARGET(p2p_transport_serialization, .init = initialize_p2p_transport_serial namespace { -template<typename R> +template<RandomNumberGenerator R> void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDataProvider& provider) { // Simulation test with two Transport objects, which send messages to each other, with @@ -165,8 +164,7 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa // Determine size of message to send (limited to 75 kB for performance reasons). size_t size = provider.ConsumeIntegralInRange<uint32_t>(0, 75000); // Get payload of message from RNG. - msg.data.resize(size); - for (auto& v : msg.data) v = uint8_t(rng()); + msg.data = rng.randbytes(size); // Return. return msg; }; @@ -337,7 +335,7 @@ std::unique_ptr<Transport> MakeV1Transport(NodeId nodeid) noexcept return std::make_unique<V1Transport>(nodeid); } -template<typename RNG> +template<RandomNumberGenerator RNG> std::unique_ptr<Transport> MakeV2Transport(NodeId nodeid, bool initiator, RNG& rng, FuzzedDataProvider& provider) { // Retrieve key @@ -353,8 +351,7 @@ std::unique_ptr<Transport> MakeV2Transport(NodeId nodeid, bool initiator, RNG& r } else { // If it's longer, generate it from the RNG. This avoids having large amounts of // (hopefully) irrelevant data needing to be stored in the fuzzer data. - garb.resize(garb_len); - for (auto& v : garb) v = uint8_t(rng()); + garb = rng.randbytes(garb_len); } // Retrieve entropy auto ent = provider.ConsumeBytes<std::byte>(32); @@ -378,7 +375,7 @@ FUZZ_TARGET(p2p_transport_bidirectional, .init = initialize_p2p_transport_serial { // Test with two V1 transports talking to each other. FuzzedDataProvider provider{buffer.data(), buffer.size()}; - XoRoShiRo128PlusPlus rng(provider.ConsumeIntegral<uint64_t>()); + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); auto t1 = MakeV1Transport(NodeId{0}); auto t2 = MakeV1Transport(NodeId{1}); if (!t1 || !t2) return; @@ -389,7 +386,7 @@ FUZZ_TARGET(p2p_transport_bidirectional_v2, .init = initialize_p2p_transport_ser { // Test with two V2 transports talking to each other. FuzzedDataProvider provider{buffer.data(), buffer.size()}; - XoRoShiRo128PlusPlus rng(provider.ConsumeIntegral<uint64_t>()); + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); auto t1 = MakeV2Transport(NodeId{0}, true, rng, provider); auto t2 = MakeV2Transport(NodeId{1}, false, rng, provider); if (!t1 || !t2) return; @@ -400,7 +397,7 @@ FUZZ_TARGET(p2p_transport_bidirectional_v1v2, .init = initialize_p2p_transport_s { // Test with a V1 initiator talking to a V2 responder. FuzzedDataProvider provider{buffer.data(), buffer.size()}; - XoRoShiRo128PlusPlus rng(provider.ConsumeIntegral<uint64_t>()); + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>()); auto t1 = MakeV1Transport(NodeId{0}); auto t2 = MakeV2Transport(NodeId{1}, false, rng, provider); if (!t1 || !t2) return; diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index a3d6ab6375..cb39b3be83 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2022 The Bitcoin Core developers +// Copyright (c) 2009-present 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,7 @@ FUZZ_TARGET(parse_univalue, .init = initialize_parse_univalue) } try { FlatSigningProvider provider; - (void)EvalDescriptorStringOrObject(univalue, provider); + if (buffer.size() < 10'000) (void)EvalDescriptorStringOrObject(univalue, provider); } catch (const UniValue&) { } catch (const std::runtime_error&) { } diff --git a/src/test/fuzz/poolresource.cpp b/src/test/fuzz/poolresource.cpp index f764d9f8db..28bf7175c0 100644 --- a/src/test/fuzz/poolresource.cpp +++ b/src/test/fuzz/poolresource.cpp @@ -2,13 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <random.h> #include <span.h> #include <support/allocators/pool.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> #include <test/util/poolresourcetester.h> -#include <test/util/xoroshiro128plusplus.h> #include <cstdint> #include <tuple> @@ -71,41 +71,14 @@ public: void RandomContentFill(Entry& entry) { - XoRoShiRo128PlusPlus rng(entry.seed); - auto ptr = entry.span.data(); - auto size = entry.span.size(); - - while (size >= 8) { - auto r = rng(); - std::memcpy(ptr, &r, 8); - size -= 8; - ptr += 8; - } - if (size > 0) { - auto r = rng(); - std::memcpy(ptr, &r, size); - } + InsecureRandomContext(entry.seed).fillrand(entry.span); } void RandomContentCheck(const Entry& entry) { - XoRoShiRo128PlusPlus rng(entry.seed); - auto ptr = entry.span.data(); - auto size = entry.span.size(); - - std::byte buf[8]; - while (size >= 8) { - auto r = rng(); - std::memcpy(buf, &r, 8); - assert(std::memcmp(buf, ptr, 8) == 0); - size -= 8; - ptr += 8; - } - if (size > 0) { - auto r = rng(); - std::memcpy(buf, &r, size); - assert(std::memcmp(buf, ptr, size) == 0); - } + std::vector<std::byte> expect(entry.span.size()); + InsecureRandomContext(entry.seed).fillrand(expect); + assert(entry.span == expect); } void Deallocate(const Entry& entry) diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index 9cea32e304..aeceb38a58 100644 --- a/src/test/fuzz/prevector.cpp +++ b/src/test/fuzz/prevector.cpp @@ -2,16 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <test/fuzz/FuzzedDataProvider.h> -#include <test/fuzz/fuzz.h> - #include <prevector.h> -#include <vector> - -#include <reverse_iterator.h> #include <serialize.h> #include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <ranges> +#include <vector> namespace { template <unsigned int N, typename T> @@ -47,7 +45,7 @@ public: assert(v == real_vector[pos]); ++pos; } - for (const T& v : reverse_iterate(pre_vector)) { + for (const T& v : pre_vector | std::views::reverse) { --pos; assert(v == real_vector[pos]); } @@ -55,7 +53,7 @@ public: assert(v == real_vector[pos]); ++pos; } - for (const T& v : reverse_iterate(const_pre_vector)) { + for (const T& v : const_pre_vector | std::views::reverse) { --pos; assert(v == real_vector[pos]); } diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index d10d9dafe8..6373eac1c3 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -42,7 +42,7 @@ void initialize_process_message() static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>( /*chain_type=*/ChainType::REGTEST, - /*extra_args=*/{"-txreconciliation"}); + {.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/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 38acd432fa..62f38967a3 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -32,7 +32,7 @@ void initialize_process_messages() { static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>( /*chain_type=*/ChainType::REGTEST, - /*extra_args=*/{"-txreconciliation"}); + {.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/random.cpp b/src/test/fuzz/random.cpp index 96668734fd..6b2d42738b 100644 --- a/src/test/fuzz/random.cpp +++ b/src/test/fuzz/random.cpp @@ -26,6 +26,5 @@ FUZZ_TARGET(random) (void)fast_random_context(); std::vector<int64_t> integrals = ConsumeRandomLengthIntegralVector<int64_t>(fuzzed_data_provider); - Shuffle(integrals.begin(), integrals.end(), fast_random_context); std::shuffle(integrals.begin(), integrals.end(), fast_random_context); } diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index 4e52c1c091..9122617e46 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -41,7 +41,7 @@ using util::ToString; namespace { struct RPCFuzzTestingSetup : public TestingSetup { - RPCFuzzTestingSetup(const ChainType chain_type, const std::vector<const char*>& extra_args) : TestingSetup{chain_type, extra_args} + RPCFuzzTestingSetup(const ChainType chain_type, TestOpts opts) : TestingSetup{chain_type, opts} { } diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index fe41a8c6ae..07a49e039f 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -94,6 +94,7 @@ FUZZ_TARGET(script, .init = initialize_script) (void)Solver(script, solutions); (void)script.HasValidOps(); + (void)script.IsPayToAnchor(); (void)script.IsPayToScriptHash(); (void)script.IsPayToWitnessScriptHash(); (void)script.IsPushOnly(); diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp index 5fdbc9e106..7f73c3706c 100644 --- a/src/test/fuzz/script_sigcache.cpp +++ b/src/test/fuzz/script_sigcache.cpp @@ -2,41 +2,41 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <chainparams.h> -#include <key.h> +#include <consensus/amount.h> +#include <primitives/transaction.h> #include <pubkey.h> +#include <script/interpreter.h> #include <script/sigcache.h> +#include <span.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> #include <test/util/setup_common.h> +#include <uint256.h> -#include <cstdint> +#include <cstddef> #include <optional> -#include <string> #include <vector> -namespace { -const BasicTestingSetup* g_setup; -} // namespace - void initialize_script_sigcache() { static const auto testing_setup = MakeNoLogFileContext<>(); - g_setup = testing_setup.get(); } FUZZ_TARGET(script_sigcache, .init = initialize_script_sigcache) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const auto max_sigcache_bytes{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, DEFAULT_SIGNATURE_CACHE_BYTES)}; + SignatureCache signature_cache{max_sigcache_bytes}; + const std::optional<CMutableTransaction> mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS); const CTransaction tx{mutable_transaction ? *mutable_transaction : CMutableTransaction{}}; const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); const CAmount amount = ConsumeMoney(fuzzed_data_provider); const bool store = fuzzed_data_provider.ConsumeBool(); PrecomputedTransactionData tx_data; - CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, tx_data}; + CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, signature_cache, tx_data}; if (fuzzed_data_provider.ConsumeBool()) { const auto random_bytes = fuzzed_data_provider.ConsumeBytes<unsigned char>(64); const XOnlyPubKey pub_key(ConsumeUInt256(fuzzed_data_provider)); diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 5b822b03f6..443d7241b5 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 The Bitcoin Core developers +// Copyright (c) 2020-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -101,7 +101,6 @@ FUZZ_TARGET(string) (void)TrimString(random_string_1, random_string_2); (void)UrlDecode(random_string_1); (void)ContainsNoNUL(random_string_1); - (void)_(random_string_1.c_str()); try { throw scriptnum_error{random_string_1}; } catch (const std::runtime_error&) { diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp index 7bebb987b1..5129c05a39 100644 --- a/src/test/fuzz/txorphan.cpp +++ b/src/test/fuzz/txorphan.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 The Bitcoin Core developers +// Copyright (c) 2022-present 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,11 +37,11 @@ FUZZ_TARGET(txorphan, .init = initialize_orphanage) SetMockTime(ConsumeTime(fuzzed_data_provider)); TxOrphanage orphanage; - std::set<COutPoint> outpoints; + std::vector<COutPoint> outpoints; // Duplicates are tolerated // initial outpoints used to construct transactions later for (uint8_t i = 0; i < 4; i++) { - outpoints.emplace(Txid::FromUint256(uint256{i}), 0); + outpoints.emplace_back(Txid::FromUint256(uint256{i}), 0); } CTransactionRef ptx_potential_parent = nullptr; @@ -67,7 +67,7 @@ FUZZ_TARGET(txorphan, .init = initialize_orphanage) auto new_tx = MakeTransactionRef(tx_mut); // add newly constructed outpoints to the coin pool for (uint32_t i = 0; i < num_out; i++) { - outpoints.emplace(new_tx->GetHash(), i); + outpoints.emplace_back(new_tx->GetHash(), i); } return new_tx; }(); diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 92ded99917..425b9559a7 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -214,6 +214,9 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}}; }, [&] { + tx_destination = PayToAnchor{}; + }, + [&] { std::vector<unsigned char> program{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/40)}; if (program.size() < 2) { program = {0, 0}; diff --git a/src/test/fuzz/util/descriptor.cpp b/src/test/fuzz/util/descriptor.cpp index 0fed2bc5e1..9e52e990a2 100644 --- a/src/test/fuzz/util/descriptor.cpp +++ b/src/test/fuzz/util/descriptor.cpp @@ -4,6 +4,9 @@ #include <test/fuzz/util/descriptor.h> +#include <ranges> +#include <stack> + void MockedDescriptorConverter::Init() { // The data to use as a private key or a seed for an xprv. std::array<std::byte, 32> key_data{std::byte{1}}; @@ -84,3 +87,59 @@ bool HasDeepDerivPath(const FuzzBufferType& buff, const int max_depth) } return false; } + +bool HasTooManySubFrag(const FuzzBufferType& buff, const int max_subs, const size_t max_nested_subs) +{ + // We use a stack because there may be many nested sub-frags. + std::stack<int> counts; + for (const auto& ch: buff) { + // The fuzzer may generate an input with a ton of parentheses. Rule out pathological cases. + if (counts.size() > max_nested_subs) return true; + + if (ch == '(') { + // A new fragment was opened, create a new sub-count for it and start as one since any fragment with + // parentheses has at least one sub. + counts.push(1); + } else if (ch == ',' && !counts.empty()) { + // When encountering a comma, account for an additional sub in the last opened fragment. If it exceeds the + // limit, bail. + if (++counts.top() > max_subs) return true; + } else if (ch == ')' && !counts.empty()) { + // Fragment closed! Drop its sub count and resume to counting the number of subs for its parent. + counts.pop(); + } + } + return false; +} + +bool HasTooManyWrappers(const FuzzBufferType& buff, const int max_wrappers) +{ + // The number of nested wrappers. Nested wrappers are always characters which follow each other so we don't have to + // use a stack as we do above when counting the number of sub-fragments. + std::optional<int> count; + + // We want to detect nested wrappers. A wrapper is a character prepended to a fragment, separated by a colon. There + // may be more than one wrapper, in which case the colon is not repeated. For instance `jjjjj:pk()`. To count + // wrappers we iterate in reverse and use the colon to detect the end of a wrapper expression and count how many + // characters there are since the beginning of the expression. We stop counting when we encounter a character + // indicating the beginning of a new expression. + for (const auto ch: buff | std::views::reverse) { + // A colon, start counting. + if (ch == ':') { + // The colon itself is not a wrapper so we start at 0. + count = 0; + } else if (count) { + // If we are counting wrappers, stop when we crossed the beginning of the wrapper expression. Otherwise keep + // counting and bail if we reached the limit. + // A wrapper may only ever occur as the first sub of a descriptor/miniscript expression ('('), as the + // first Taproot leaf in a pair ('{') or as the nth sub in each case (','). + if (ch == ',' || ch == '(' || ch == '{') { + count.reset(); + } else if (++*count > max_wrappers) { + return true; + } + } + } + + return false; +} diff --git a/src/test/fuzz/util/descriptor.h b/src/test/fuzz/util/descriptor.h index cd41dbafa3..ea928c39f0 100644 --- a/src/test/fuzz/util/descriptor.h +++ b/src/test/fuzz/util/descriptor.h @@ -55,4 +55,25 @@ constexpr int MAX_DEPTH{2}; */ bool HasDeepDerivPath(const FuzzBufferType& buff, const int max_depth = MAX_DEPTH); +//! Default maximum number of sub-fragments. +constexpr int MAX_SUBS{1'000}; +//! Maximum number of nested sub-fragments we'll allow in a descriptor. +constexpr size_t MAX_NESTED_SUBS{10'000}; + +/** + * Whether the buffer, if it represents a valid descriptor, contains a fragment with more + * sub-fragments than the given maximum. + */ +bool HasTooManySubFrag(const FuzzBufferType& buff, const int max_subs = MAX_SUBS, + const size_t max_nested_subs = MAX_NESTED_SUBS); + +//! Default maximum number of wrappers per fragment. +constexpr int MAX_WRAPPERS{100}; + +/** + * Whether the buffer, if it represents a valid descriptor, contains a fragment with more + * wrappers than the given maximum. + */ +bool HasTooManyWrappers(const FuzzBufferType& buff, const int max_wrappers = MAX_WRAPPERS); + #endif // BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp index ad69c29d12..ca0fd65cae 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -383,7 +383,7 @@ bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* return false; } if (occurred != nullptr) { - // We simulate the requested event as occured when ConsumeBool() + // We simulate the requested event as occurred when ConsumeBool() // returns false. This avoids simulating endless waiting if the // FuzzedDataProvider runs out of data. *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested; @@ -395,7 +395,7 @@ bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& even { for (auto& [sock, events] : events_per_sock) { (void)sock; - // We simulate the requested event as occured when ConsumeBool() + // We simulate the requested event as occurred when ConsumeBool() // returns false. This avoids simulating endless waiting if the // FuzzedDataProvider runs out of data. events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested; diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index fa608385d9..1d90414443 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -31,7 +31,13 @@ void initialize_chain() FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - std::unique_ptr<const TestingSetup> setup{MakeNoLogFileContext<const TestingSetup>()}; + std::unique_ptr<const TestingSetup> setup{ + MakeNoLogFileContext<const TestingSetup>( + ChainType::REGTEST, + TestOpts{ + .setup_net = false, + .setup_validation_interface = false, + })}; const auto& node = setup->m_node; auto& chainman{*node.chainman}; @@ -41,13 +47,39 @@ FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) { AutoFile outfile{fsbridge::fopen(snapshot_path, "wb")}; - const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; - outfile << Span{file_data}; + // Metadata + if (fuzzed_data_provider.ConsumeBool()) { + std::vector<uint8_t> metadata{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; + outfile << Span{metadata}; + } else { + DataStream data_stream{}; + auto msg_start = chainman.GetParams().MessageStart(); + int base_blockheight{fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 2 * COINBASE_MATURITY)}; + uint256 base_blockhash{g_chain->at(base_blockheight - 1)->GetHash()}; + uint64_t m_coins_count{fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(1, 3 * COINBASE_MATURITY)}; + SnapshotMetadata metadata{msg_start, base_blockhash, m_coins_count}; + outfile << metadata; + } + // Coins + if (fuzzed_data_provider.ConsumeBool()) { + std::vector<uint8_t> file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; + outfile << Span{file_data}; + } else { + int height{0}; + for (const auto& block : *g_chain) { + auto coinbase{block->vtx.at(0)}; + outfile << coinbase->GetHash(); + WriteCompactSize(outfile, 1); // number of coins for the hash + WriteCompactSize(outfile, 0); // index of coin + outfile << Coin(coinbase->vout[0], height, /*fCoinBaseIn=*/1); + height++; + } + } } const auto ActivateFuzzedSnapshot{[&] { AutoFile infile{fsbridge::fopen(snapshot_path, "rb")}; - auto msg_start = Params().MessageStart(); + auto msg_start = chainman.GetParams().MessageStart(); SnapshotMetadata metadata{msg_start}; try { infile >> metadata; @@ -73,16 +105,20 @@ FUZZ_TARGET(utxo_snapshot, .init = initialize_chain) Assert(*chainman.ActiveChainstate().m_from_snapshot_blockhash == *chainman.SnapshotBlockhash()); const auto& coinscache{chainman.ActiveChainstate().CoinsTip()}; - int64_t chain_tx{}; for (const auto& block : *g_chain) { Assert(coinscache.HaveCoin(COutPoint{block->vtx.at(0)->GetHash(), 0})); const auto* index{chainman.m_blockman.LookupBlockIndex(block->GetHash())}; - const auto num_tx{Assert(index)->nTx}; - Assert(num_tx == 1); - chain_tx += num_tx; + Assert(index); + Assert(index->nTx == 0); + if (index->nHeight == chainman.GetSnapshotBaseHeight()) { + auto params{chainman.GetParams().AssumeutxoForHeight(index->nHeight)}; + Assert(params.has_value()); + Assert(params.value().m_chain_tx_count == index->m_chain_tx_count); + } else { + Assert(index->m_chain_tx_count == 0); + } } Assert(g_chain->size() == coinscache.GetCacheSize()); - Assert(chain_tx == chainman.ActiveTip()->nChainTx); } else { Assert(!chainman.SnapshotBlockhash()); Assert(!chainman.ActiveChainstate().m_from_snapshot_blockhash); diff --git a/src/test/fuzz/utxo_total_supply.cpp b/src/test/fuzz/utxo_total_supply.cpp index 48ed266abe..b0f1a1251a 100644 --- a/src/test/fuzz/utxo_total_supply.cpp +++ b/src/test/fuzz/utxo_total_supply.cpp @@ -23,7 +23,7 @@ FUZZ_TARGET(utxo_total_supply) ChainTestingSetup test_setup{ ChainType::REGTEST, { - "-testactivationheight=bip34@2", + .extra_args = {"-testactivationheight=bip34@2"}, }, }; // Create chainstate diff --git a/src/test/fuzz/vecdeque.cpp b/src/test/fuzz/vecdeque.cpp index 1d9a98931f..3bb858ee8a 100644 --- a/src/test/fuzz/vecdeque.cpp +++ b/src/test/fuzz/vecdeque.cpp @@ -2,9 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <random.h> #include <span.h> #include <test/fuzz/util.h> -#include <test/util/xoroshiro128plusplus.h> #include <util/vecdeque.h> #include <deque> @@ -28,7 +28,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) { FuzzedDataProvider provider(buffer.data(), buffer.size()); // Local RNG, only used for the seeds to initialize T objects with. - XoRoShiRo128PlusPlus rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak); + InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>() ^ rng_tweak); // Real circular buffers. std::vector<VecDeque<T>> real; @@ -175,7 +175,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* push_back() (copying) */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); real[idx].push_back(*tmp); @@ -191,7 +191,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* push_back() (moving) */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); sim[idx].push_back(*tmp); @@ -207,7 +207,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* emplace_back() */ - uint64_t seed{rng()}; + uint64_t seed{rng.rand64()}; size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); sim[idx].emplace_back(seed); @@ -223,7 +223,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* push_front() (copying) */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); real[idx].push_front(*tmp); @@ -239,7 +239,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* push_front() (moving) */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); sim[idx].push_front(*tmp); @@ -255,7 +255,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_full && command-- == 0) { /* emplace_front() */ - uint64_t seed{rng()}; + uint64_t seed{rng.rand64()}; size_t old_size = real[idx].size(); size_t old_cap = real[idx].capacity(); sim[idx].emplace_front(seed); @@ -271,7 +271,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_empty && command-- == 0) { /* front() [modifying] */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); assert(sim[idx].front() == real[idx].front()); sim[idx].front() = *tmp; @@ -281,7 +281,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_empty && command-- == 0) { /* back() [modifying] */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t old_size = real[idx].size(); assert(sim[idx].back() == real[idx].back()); sim[idx].back() = *tmp; @@ -291,7 +291,7 @@ void TestType(Span<const uint8_t> buffer, uint64_t rng_tweak) } if (existing_buffer_non_empty && command-- == 0) { /* operator[] [modifying] */ - tmp = T(rng()); + tmp = T(rng.rand64()); size_t pos = provider.ConsumeIntegralInRange<size_t>(0, sim[idx].size() - 1); size_t old_size = real[idx].size(); assert(sim[idx][pos] == real[idx][pos]); diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 51f1d4c840..150e386c2d 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(siphash) hasher.Write(0x2F2E2D2C2B2A2928ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull); - BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100")), 0x7127512f72f27cceull); + BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256{"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"}), 0x7127512f72f27cceull); // Check test vectors from spec, one byte at a time CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp index 0512c6134f..bb9ca88019 100644 --- a/src/test/i2p_tests.cpp +++ b/src/test/i2p_tests.cpp @@ -23,8 +23,8 @@ class EnvTestingSetup : public BasicTestingSetup { public: explicit EnvTestingSetup(const ChainType chainType = ChainType::MAIN, - const std::vector<const char*>& extra_args = {}) - : BasicTestingSetup{chainType, extra_args}, + TestOpts opts = {}) + : BasicTestingSetup{chainType, opts}, m_prev_log_level{LogInstance().LogLevel()}, m_create_sock_orig{CreateSock} { diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index b897a0a153..112d6db193 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -8,6 +8,7 @@ #include <key_io.h> #include <span.h> #include <streams.h> +#include <secp256k1_extrakeys.h> #include <test/util/random.h> #include <test/util/setup_common.h> #include <uint256.h> @@ -299,6 +300,13 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors) // Verify those signatures for good measure. BOOST_CHECK(pubkey.VerifySchnorr(msg256, sig64)); + // Repeat the same check, but use the KeyPair directly without any merkle tweak + KeyPair keypair = key.ComputeKeyPair(/*merkle_root=*/nullptr); + bool kp_ok = keypair.SignSchnorr(msg256, sig64, aux256); + BOOST_CHECK(kp_ok); + BOOST_CHECK(pubkey.VerifySchnorr(msg256, sig64)); + BOOST_CHECK(std::vector<unsigned char>(sig64, sig64 + 64) == sig); + // Do 10 iterations where we sign with a random Merkle root to tweak, // and compare against the resulting tweaked keys, with random aux. // In iteration i=0 we tweak with empty Merkle tree. @@ -312,6 +320,12 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors) bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256); BOOST_CHECK(ok); BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64)); + + // Repeat the same check, but use the KeyPair class directly + KeyPair keypair = key.ComputeKeyPair(&merkle_root); + bool kp_ok = keypair.SignSchnorr(msg256, sig64, aux256); + BOOST_CHECK(kp_ok); + BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64)); } } } @@ -345,4 +359,31 @@ BOOST_AUTO_TEST_CASE(bip341_test_h) BOOST_CHECK(XOnlyPubKey::NUMS_H == H); } +BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test) +{ + // Sanity check to ensure we get the same tweak using CPubKey vs secp256k1 functions + secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + CKey key; + key.MakeNewKey(true); + uint256 merkle_root = InsecureRand256(); + + // secp256k1 functions + secp256k1_keypair keypair; + BOOST_CHECK(secp256k1_keypair_create(secp256k1_context_sign, &keypair, UCharCast(key.begin()))); + secp256k1_xonly_pubkey xonly_pubkey; + BOOST_CHECK(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &xonly_pubkey, nullptr, &keypair)); + unsigned char xonly_bytes[32]; + BOOST_CHECK(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, xonly_bytes, &xonly_pubkey)); + uint256 tweak_old = XOnlyPubKey(xonly_bytes).ComputeTapTweakHash(&merkle_root); + + // CPubKey + CPubKey pubkey = key.GetPubKey(); + uint256 tweak_new = XOnlyPubKey(pubkey).ComputeTapTweakHash(&merkle_root); + + BOOST_CHECK_EQUAL(tweak_old, tweak_new); + + secp256k1_context_destroy(secp256k1_context_sign); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp index 9c6008bdca..73dbe33714 100644 --- a/src/test/merkleblock_tests.cpp +++ b/src/test/merkleblock_tests.cpp @@ -24,10 +24,10 @@ BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_found) std::set<Txid> txids; // Last txn in block. - Txid txhash1{TxidFromString("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")}; + Txid txhash1{Txid::FromHex("74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20").value()}; // Second txn in block. - Txid txhash2{TxidFromString("0xf9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07")}; + Txid txhash2{Txid::FromHex("f9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07").value()}; txids.insert(txhash1); txids.insert(txhash2); @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_not_found) CBlock block = getBlock13b8a(); std::set<Txid> txids2; - txids2.insert(TxidFromString("0xc0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); + txids2.insert(Txid::FromHex("c0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20").value()); CMerkleBlock merkleBlock(block, txids2); BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex()); diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 7e39e9e4de..815c278b8c 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -48,9 +48,9 @@ struct TestData { TestData() { // All our signatures sign (and are required to sign) this constant message. - auto const MESSAGE_HASH = uint256S("f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"); + constexpr uint256 MESSAGE_HASH{"0000000000000000f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"}; // We don't pass additional randomness when creating a schnorr signature. - auto const EMPTY_AUX{uint256S("")}; + const auto EMPTY_AUX{uint256::ZERO}; // We generate 255 public keys and 255 hashes of each type. for (int i = 1; i <= 255; ++i) { @@ -346,7 +346,7 @@ void TestSatisfy(const KeyConverter& converter, const std::string& testcase, con 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); + std::shuffle(challist.begin(), challist.end(), g_insecure_rand_ctx); Satisfier satisfier(converter.MsContext()); TestSignatureChecker checker(satisfier); bool prev_mal_success = false, prev_nonmal_success = false; @@ -699,6 +699,12 @@ BOOST_AUTO_TEST_CASE(fixed_tests) const auto insane_sub = ms_ins->FindInsaneSub(); BOOST_CHECK(insane_sub && *insane_sub->ToString(wsh_converter) == "and_b(after(1),a:after(1000000000))"); + // Numbers can't be prefixed by a sign. + BOOST_CHECK(!miniscript::FromString("after(-1)", wsh_converter)); + BOOST_CHECK(!miniscript::FromString("after(+1)", wsh_converter)); + BOOST_CHECK(!miniscript::FromString("thresh(-1,pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204))", wsh_converter)); + BOOST_CHECK(!miniscript::FromString("multi(+1,03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)", wsh_converter)); + // Timelock tests Test("after(100)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only heightlock Test("after(1000000000)", "?", "?", TESTMODE_VALID | TESTMODE_NONMAL); // only timelock diff --git a/src/test/net_peer_connection_tests.cpp b/src/test/net_peer_connection_tests.cpp index 5f38ce112c..2dde6daee5 100644 --- a/src/test/net_peer_connection_tests.cpp +++ b/src/test/net_peer_connection_tests.cpp @@ -31,7 +31,7 @@ struct LogIPsTestingSetup : public TestingSetup { LogIPsTestingSetup() - : TestingSetup{ChainType::MAIN, /*extra_args=*/{"-logips"}} {} + : TestingSetup{ChainType::MAIN, {.extra_args = {"-logips"}}} {} }; BOOST_FIXTURE_TEST_SUITE(net_peer_connection_tests, LogIPsTestingSetup) diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp index 51d6c4384a..d9e1c2332e 100644 --- a/src/test/net_peer_eviction_tests.cpp +++ b/src/test/net_peer_eviction_tests.cpp @@ -31,7 +31,7 @@ bool IsProtected(int num_peers, for (NodeEvictionCandidate& candidate : candidates) { candidate_setup_fn(candidate); } - Shuffle(candidates.begin(), candidates.end(), random_context); + std::shuffle(candidates.begin(), candidates.end(), random_context); const size_t size{candidates.size()}; const size_t expected{size - size / 2}; // Expect half the candidates will be protected. @@ -572,7 +572,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // Returns true if any of the node ids in node_ids are selected for eviction. bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::unordered_set<NodeId>& node_ids, FastRandomContext& random_context) { - Shuffle(candidates.begin(), candidates.end(), random_context); + std::shuffle(candidates.begin(), candidates.end(), random_context); const std::optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates)); if (!evicted_node_id) { return false; diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp index 450bf6a4fc..d2dab94526 100644 --- a/src/test/orphanage_tests.cpp +++ b/src/test/orphanage_tests.cpp @@ -21,15 +21,13 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) class TxOrphanageTest : public TxOrphanage { public: - inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + inline size_t CountOrphans() const { - LOCK(m_mutex); return m_orphans.size(); } - CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + CTransactionRef RandomOrphan() { - LOCK(m_mutex); std::map<Wtxid, OrphanTx>::iterator it; it = m_orphans.lower_bound(Wtxid::FromUint256(InsecureRand256())); if (it == m_orphans.end()) @@ -106,7 +104,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) // ecdsa_signature_parse_der_lax are executed during this test. // Specifically branches that run only when an ECDSA // signature's R and S values have leading zeros. - g_insecure_rand_ctx = FastRandomContext{uint256{33}}; + g_insecure_rand_ctx.Reseed(uint256{33}); TxOrphanageTest orphanage; CKey key; @@ -114,6 +112,10 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) FillableSigningProvider keystore; BOOST_CHECK(keystore.AddKey(key)); + // Freeze time for length of test + auto now{GetTime<std::chrono::seconds>()}; + SetMockTime(now); + // 50 orphan transactions: for (int i = 0; i < 50; i++) { @@ -172,22 +174,52 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i)); } - // Test EraseOrphansFor: + size_t expected_num_orphans = orphanage.CountOrphans(); + + // Non-existent peer; nothing should be deleted + orphanage.EraseForPeer(/*peer=*/-1); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans); + + // Each of first three peers stored + // two transactions each. for (NodeId i = 0; i < 3; i++) { - size_t sizeBefore = orphanage.CountOrphans(); orphanage.EraseForPeer(i); - BOOST_CHECK(orphanage.CountOrphans() < sizeBefore); + expected_num_orphans -= 2; + BOOST_CHECK(orphanage.CountOrphans() == expected_num_orphans); } - // Test LimitOrphanTxSize() function: + // Test LimitOrphanTxSize() function, nothing should timeout: FastRandomContext rng{/*fDeterministic=*/true}; + orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans); + expected_num_orphans -= 1; + orphanage.LimitOrphans(/*max_orphans=*/expected_num_orphans, rng); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), expected_num_orphans); + assert(expected_num_orphans > 40); orphanage.LimitOrphans(40, rng); - BOOST_CHECK(orphanage.CountOrphans() <= 40); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 40); orphanage.LimitOrphans(10, rng); - BOOST_CHECK(orphanage.CountOrphans() <= 10); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 10); orphanage.LimitOrphans(0, rng); - BOOST_CHECK(orphanage.CountOrphans() == 0); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0); + + // Add one more orphan, check timeout logic + auto timeout_tx = MakeTransactionSpending(/*outpoints=*/{}, rng); + orphanage.AddTx(timeout_tx, 0); + orphanage.LimitOrphans(1, rng); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1); + + // One second shy of expiration + SetMockTime(now + ORPHAN_TX_EXPIRE_TIME - 1s); + orphanage.LimitOrphans(1, rng); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1); + + // Jump one more second, orphan should be timed out on limiting + SetMockTime(now + ORPHAN_TX_EXPIRE_TIME); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 1); + orphanage.LimitOrphans(1, rng); + BOOST_CHECK_EQUAL(orphanage.CountOrphans(), 0); } BOOST_AUTO_TEST_CASE(same_txid_diff_witness) diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index edecf70c6f..5b7ccc8e7a 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -29,10 +29,10 @@ BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(pmt_test1) { - static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; + static const unsigned int tx_counts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; for (int i = 0; i < 12; i++) { - unsigned int nTx = nTxCounts[i]; + unsigned int nTx = tx_counts[i]; // build a block with some dummy transactions CBlock block; diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 3a44d1da49..4af66af283 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target) uint256 hash; unsigned int nBits; nBits = UintToArith256(consensus.powLimit).GetCompact(true); - hash.SetHex("0x1"); + hash = uint256{1}; BOOST_CHECK(!CheckProofOfWork(hash, nBits, consensus)); } @@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target) const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits{~0x00800000U}; - hash.SetHex("0x1"); + hash = uint256{1}; BOOST_CHECK(!CheckProofOfWork(hash, nBits, consensus)); } @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_too_easy_target) arith_uint256 nBits_arith = UintToArith256(consensus.powLimit); nBits_arith *= 2; nBits = nBits_arith.GetCompact(); - hash.SetHex("0x1"); + hash = uint256{1}; BOOST_CHECK(!CheckProofOfWork(hash, nBits, consensus)); } @@ -177,7 +177,7 @@ void sanity_check_chainparams(const ArgsManager& args, ChainType chain_type) // check max target * 4*nPowTargetTimespan doesn't overflow -- see pow.cpp:CalculateNextWorkRequired() if (!consensus.fPowNoRetargeting) { - arith_uint256 targ_max{UintToArith256(uint256S("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))}; + arith_uint256 targ_max{UintToArith256(uint256{"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"})}; targ_max /= consensus.nPowTargetTimespan*4; BOOST_CHECK(UintToArith256(consensus.powLimit) < targ_max); } @@ -198,6 +198,11 @@ BOOST_AUTO_TEST_CASE(ChainParams_TESTNET_sanity) sanity_check_chainparams(*m_node.args, ChainType::TESTNET); } +BOOST_AUTO_TEST_CASE(ChainParams_TESTNET4_sanity) +{ + sanity_check_chainparams(*m_node.args, ChainType::TESTNET4); +} + BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity) { sanity_check_chainparams(*m_node.args, ChainType::SIGNET); diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index 1559011fcd..f5f0cbee58 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -3,17 +3,16 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <prevector.h> -#include <vector> - -#include <reverse_iterator.h> #include <serialize.h> #include <streams.h> - #include <test/util/random.h> #include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> +#include <ranges> +#include <vector> + BOOST_FIXTURE_TEST_SUITE(prevector_tests, TestingSetup) template<unsigned int N, typename T> @@ -58,14 +57,14 @@ class prevector_tester { for (const T& v : pre_vector) { local_check(v == real_vector[pos++]); } - for (const T& v : reverse_iterate(pre_vector)) { - local_check(v == real_vector[--pos]); + for (const T& v : pre_vector | std::views::reverse) { + local_check(v == real_vector[--pos]); } for (const T& v : const_pre_vector) { local_check(v == real_vector[pos++]); } - for (const T& v : reverse_iterate(const_pre_vector)) { - local_check(v == real_vector[--pos]); + for (const T& v : const_pre_vector | std::views::reverse) { + local_check(v == real_vector[--pos]); } DataStream ss1{}; DataStream ss2{}; @@ -210,9 +209,9 @@ public: } prevector_tester() { - SeedInsecureRand(); + SeedRandomForTest(); rand_seed = InsecureRand256(); - rand_cache = FastRandomContext(rand_seed); + rand_cache.Reseed(rand_seed); } }; diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 43d887b5c9..3d8b543e64 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -20,28 +20,39 @@ BOOST_AUTO_TEST_CASE(osrandom_tests) BOOST_CHECK(Random_SanityCheck()); } -BOOST_AUTO_TEST_CASE(fastrandom_tests) +BOOST_AUTO_TEST_CASE(fastrandom_tests_deterministic) { // Check that deterministic FastRandomContexts are deterministic - g_mock_deterministic_tests = true; - FastRandomContext ctx1(true); - FastRandomContext ctx2(true); - - for (int i = 10; i > 0; --i) { - BOOST_CHECK_EQUAL(GetRand<uint64_t>(), uint64_t{10393729187455219830U}); - BOOST_CHECK_EQUAL(GetRand<int>(), int{769702006}); - BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654); - BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374); + SeedRandomForTest(SeedRand::ZEROS); + FastRandomContext ctx1{true}; + FastRandomContext ctx2{true}; + + { + BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{9330418229102544152u}); + BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{618925161}); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 1271170921); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2803534); + + BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{10170981140880778086u}); + BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{1689082725}); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 2464643716); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2312205); + + BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{5689404004456455543u}); + BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{785839937}); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 93558804); + BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 507022); } + { constexpr SteadySeconds time_point{1s}; FastRandomContext ctx{true}; BOOST_CHECK_EQUAL(7, ctx.rand_uniform_delay(time_point, 9s).time_since_epoch().count()); BOOST_CHECK_EQUAL(-6, ctx.rand_uniform_delay(time_point, -9s).time_since_epoch().count()); BOOST_CHECK_EQUAL(1, ctx.rand_uniform_delay(time_point, 0s).time_since_epoch().count()); - BOOST_CHECK_EQUAL(1467825113502396065, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count()); - BOOST_CHECK_EQUAL(-970181367944767837, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count()); - BOOST_CHECK_EQUAL(24761, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count()); + BOOST_CHECK_EQUAL(4652286523065884857, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(-8813961240025683129, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(26443, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count()); } BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); @@ -65,15 +76,28 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) // Check with time-point type BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count()); } +} +BOOST_AUTO_TEST_CASE(fastrandom_tests_nondeterministic) +{ // Check that a nondeterministic ones are not - g_mock_deterministic_tests = false; - for (int i = 10; i > 0; --i) { - BOOST_CHECK(GetRand<uint64_t>() != uint64_t{10393729187455219830U}); - BOOST_CHECK(GetRand<int>() != int{769702006}); - BOOST_CHECK(GetRandMicros(std::chrono::hours{1}) != std::chrono::microseconds{2917185654}); - BOOST_CHECK(GetRandMillis(std::chrono::hours{1}) != std::chrono::milliseconds{2144374}); + { + BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{9330418229102544152u}); + BOOST_CHECK(FastRandomContext().rand<int>() != int{618925161}); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 1271170921); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2803534); + + BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{10170981140880778086u}); + BOOST_CHECK(FastRandomContext().rand<int>() != int{1689082725}); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 2464643716); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2312205); + + BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{5689404004456455543u}); + BOOST_CHECK(FastRandomContext().rand<int>() != int{785839937}); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 93558804); + BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 507022); } + { FastRandomContext ctx3, ctx4; BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal @@ -103,6 +127,70 @@ BOOST_AUTO_TEST_CASE(fastrandom_randbits) } } +/** Verify that RandomMixin::randbits returns 0 and 1 for every requested bit. */ +BOOST_AUTO_TEST_CASE(randbits_test) +{ + FastRandomContext ctx_lens; //!< RNG for producing the lengths requested from ctx_test. + FastRandomContext ctx_test1(true), ctx_test2(true); //!< The RNGs being tested. + int ctx_test_bitsleft{0}; //!< (Assumed value of) ctx_test::bitbuf_len + + // Run the entire test 5 times. + for (int i = 0; i < 5; ++i) { + // count (first) how often it has occurred, and (second) how often it was true: + // - for every bit position, in every requested bits count (0 + 1 + 2 + ... + 64 = 2080) + // - for every value of ctx_test_bitsleft (0..63 = 64) + std::vector<std::pair<uint64_t, uint64_t>> seen(2080 * 64); + while (true) { + // Loop 1000 times, just to not continuously check std::all_of. + for (int j = 0; j < 1000; ++j) { + // Decide on a number of bits to request (0 through 64, inclusive; don't use randbits/randrange). + int bits = ctx_lens.rand64() % 65; + // Generate that many bits. + uint64_t gen = ctx_test1.randbits(bits); + // For certain bits counts, also test randbits<Bits> and compare. + uint64_t gen2; + if (bits == 0) { + gen2 = ctx_test2.randbits<0>(); + } else if (bits == 1) { + gen2 = ctx_test2.randbits<1>(); + } else if (bits == 7) { + gen2 = ctx_test2.randbits<7>(); + } else if (bits == 32) { + gen2 = ctx_test2.randbits<32>(); + } else if (bits == 51) { + gen2 = ctx_test2.randbits<51>(); + } else if (bits == 64) { + gen2 = ctx_test2.randbits<64>(); + } else { + gen2 = ctx_test2.randbits(bits); + } + BOOST_CHECK_EQUAL(gen, gen2); + // Make sure the result is in range. + if (bits < 64) BOOST_CHECK_EQUAL(gen >> bits, 0); + // Mark all the seen bits in the output. + for (int bit = 0; bit < bits; ++bit) { + int idx = bit + (bits * (bits - 1)) / 2 + 2080 * ctx_test_bitsleft; + seen[idx].first += 1; + seen[idx].second += (gen >> bit) & 1; + } + // Update ctx_test_bitself. + if (bits > ctx_test_bitsleft) { + ctx_test_bitsleft = ctx_test_bitsleft + 64 - bits; + } else { + ctx_test_bitsleft -= bits; + } + } + // Loop until every bit position/combination is seen 242 times. + if (std::all_of(seen.begin(), seen.end(), [](const auto& x) { return x.first >= 242; })) break; + } + // Check that each bit appears within 7.78 standard deviations of 50% + // (each will fail with P < 1/(2080 * 64 * 10^9)). + for (const auto& val : seen) { + assert(fabs(val.first * 0.5 - val.second) < sqrt(val.first * 0.25) * 7.78); + } + } +} + /** Does-it-compile test for compatibility with standard library RNG interface. */ BOOST_AUTO_TEST_CASE(stdrandom_test) { @@ -118,10 +206,6 @@ BOOST_AUTO_TEST_CASE(stdrandom_test) for (int j = 1; j <= 10; ++j) { BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end()); } - Shuffle(test.begin(), test.end(), ctx); - for (int j = 1; j <= 10; ++j) { - BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end()); - } } } @@ -132,7 +216,7 @@ BOOST_AUTO_TEST_CASE(shuffle_stat_test) uint32_t counts[5 * 5 * 5 * 5 * 5] = {0}; for (int i = 0; i < 12000; ++i) { int data[5] = {0, 1, 2, 3, 4}; - Shuffle(std::begin(data), std::end(data), ctx); + std::shuffle(std::begin(data), std::end(data), ctx); int pos = data[0] + data[1] * 5 + data[2] * 25 + data[3] * 125 + data[4] * 625; ++counts[pos]; } @@ -155,4 +239,21 @@ BOOST_AUTO_TEST_CASE(shuffle_stat_test) BOOST_CHECK_EQUAL(sum, 12000U); } +BOOST_AUTO_TEST_CASE(xoroshiro128plusplus_reference_values) +{ + // numbers generated from reference implementation + InsecureRandomContext rng(0); + BOOST_TEST(0x6f68e1e7e2646ee1 == rng()); + BOOST_TEST(0xbf971b7f454094ad == rng()); + BOOST_TEST(0x48f2de556f30de38 == rng()); + BOOST_TEST(0x6ea7c59f89bbfc75 == rng()); + + // seed with a random number + rng.Reseed(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/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 54dcc218b9..f91203cc48 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -113,13 +113,14 @@ BOOST_AUTO_TEST_CASE(sign) } // 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: + SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES}; for (int i = 0; i < 8; i++) { PrecomputedTransactionData txdata(txTo[i]); for (int j = 0; j < 8; j++) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], CTransaction(txTo[i]), 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)(); + bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], CTransaction(txTo[i]), signature_cache, 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)(); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 29e2d4a569..6befd9ba85 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -128,6 +128,20 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK(solutions[0] == std::vector<unsigned char>{16}); BOOST_CHECK(solutions[1] == ToByteVector(uint256::ONE)); + // TxoutType::ANCHOR + std::vector<unsigned char> anchor_bytes{0x4e, 0x73}; + s.clear(); + s << OP_1 << anchor_bytes; + BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::ANCHOR); + BOOST_CHECK(solutions.empty()); + + // Sanity-check IsPayToAnchor + int version{-1}; + std::vector<unsigned char> witness_program; + BOOST_CHECK(s.IsPayToAnchor()); + BOOST_CHECK(s.IsWitnessProgram(version, witness_program)); + BOOST_CHECK(CScript::IsPayToAnchor(version, witness_program)); + // TxoutType::NONSTANDARD s.clear(); s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; @@ -186,6 +200,18 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) s.clear(); s << OP_0 << std::vector<unsigned char>(19, 0x01); BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD); + + // TxoutType::ANCHOR but wrong witness version + s.clear(); + s << OP_2 << std::vector<unsigned char>{0x4e, 0x73}; + BOOST_CHECK(!s.IsPayToAnchor()); + BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_UNKNOWN); + + // TxoutType::ANCHOR but wrong 2-byte data push + s.clear(); + s << OP_1 << std::vector<unsigned char>{0xff, 0xff}; + BOOST_CHECK(!s.IsPayToAnchor()); + BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::WITNESS_UNKNOWN); } BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) @@ -367,7 +393,7 @@ BOOST_AUTO_TEST_CASE(script_standard_taproot_builder) XOnlyPubKey key_2{ParseHex("f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")}; CScript script_1 = CScript() << ToByteVector(key_1) << OP_CHECKSIG; CScript script_2 = CScript() << ToByteVector(key_2) << OP_CHECKSIG; - uint256 hash_3 = uint256S("31fe7061656bea2a36aa60a2f7ef940578049273746935d296426dc0afd86b68"); + constexpr uint256 hash_3{"31fe7061656bea2a36aa60a2f7ef940578049273746935d296426dc0afd86b68"}; TaprootBuilder builder; BOOST_CHECK(builder.IsValid() && builder.IsComplete()); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 39b53295e7..c5a8f2dfbc 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1277,6 +1277,19 @@ BOOST_AUTO_TEST_CASE(sign_invalid_miniscript) BOOST_CHECK(!SignSignature(keystore, CTransaction(prev), curr, 0, SIGHASH_ALL, sig_data)); } +/* P2A input should be considered signed. */ +BOOST_AUTO_TEST_CASE(sign_paytoanchor) +{ + FillableSigningProvider keystore; + SignatureData sig_data; + CMutableTransaction prev, curr; + prev.vout.emplace_back(0, GetScriptForDestination(PayToAnchor{})); + + curr.vin.emplace_back(COutPoint{prev.GetHash(), 0}); + + BOOST_CHECK(SignSignature(keystore, CTransaction(prev), curr, 0, SIGHASH_ALL, sig_data)); +} + BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; @@ -1526,7 +1539,7 @@ static std::vector<unsigned int> AllConsensusFlags() /** Precomputed list of all valid combinations of consensus-relevant script validation flags. */ static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags(); -static void AssetTest(const UniValue& test) +static void AssetTest(const UniValue& test, SignatureCache& signature_cache) { BOOST_CHECK(test.isObject()); @@ -1543,7 +1556,7 @@ static void AssetTest(const UniValue& test) CTransaction tx(mtx); PrecomputedTransactionData txdata; txdata.Init(tx, std::vector<CTxOut>(prevouts)); - CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata); + CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata); for (const auto flags : ALL_CONSENSUS_FLAGS) { // "final": true tests are valid for all flags. Others are only valid with flags that are @@ -1561,7 +1574,7 @@ static void AssetTest(const UniValue& test) CTransaction tx(mtx); PrecomputedTransactionData txdata; txdata.Init(tx, std::vector<CTxOut>(prevouts)); - CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata); + CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata); for (const auto flags : ALL_CONSENSUS_FLAGS) { // If a test is supposed to fail with test_flags, it should also fail with any superset thereof. @@ -1577,6 +1590,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test) { // See src/test/fuzz/script_assets_test_minimizer.cpp for information on how to generate // the script_assets_test.json file used by this test. + SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES}; const char* dir = std::getenv("DIR_UNIT_TEST_DATA"); BOOST_WARN_MESSAGE(dir != nullptr, "Variable DIR_UNIT_TEST_DATA unset, skipping script_assets_test"); @@ -1597,7 +1611,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test) BOOST_CHECK(tests.size() > 0); for (size_t i = 0; i < tests.size(); i++) { - AssetTest(tests[i]); + AssetTest(tests[i], signature_cache); } file.close(); } @@ -1678,17 +1692,17 @@ 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"); + constexpr uint256 hash1{"8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"}; + constexpr uint256 hash2{"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"}; + constexpr uint256 result{"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"); + constexpr uint8_t script[6] = {'f','o','o','b','a','r'}; + constexpr uint256 tlc0{"edbc10c272a1215dcdcc11d605b9027b5ad6ed97cd45521203f136767b5b9c06"}; + constexpr uint256 tlc2{"8b5c4f90ae6bf76e259dbef5d8a59df06359c391b59263741b25eca76451b27a"}; BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc0, Span(script)), tlc0); BOOST_CHECK_EQUAL(ComputeTapleafHash(0xc2, Span(script)), tlc2); diff --git a/src/test/serfloat_tests.cpp b/src/test/serfloat_tests.cpp index 304541074f..51c026e2ed 100644 --- a/src/test/serfloat_tests.cpp +++ b/src/test/serfloat_tests.cpp @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(doubles) for (int i = 0; i < 1000; i++) { ss << EncodeDouble(i); } - BOOST_CHECK(Hash(ss) == uint256S("43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96")); + BOOST_CHECK(Hash(ss) == uint256{"43d0c82591953c4eafe114590d392676a01585d25b25d433557f0d7878b23f96"}); // decode for (int i = 0; i < 1000; i++) { diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index e666e11758..9296cbb41c 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -30,8 +30,7 @@ BOOST_AUTO_TEST_CASE(xor_file) } { #ifdef __MINGW64__ - // Our usage of mingw-w64 and the msvcrt runtime does not support - // the x modifier for the _wfopen(). + // Temporary workaround for https://github.com/bitcoin/bitcoin/issues/30210 const char* mode = "wb"; #else const char* mode = "wbx"; @@ -436,7 +435,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_skip) BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) { // Make this test deterministic. - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp"; for (int rep = 0; rep < 50; ++rep) { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 34176626f0..5622632e97 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -17,6 +17,7 @@ #include <policy/settings.h> #include <script/script.h> #include <script/script_error.h> +#include <script/sigcache.h> #include <script/sign.h> #include <script/signingprovider.h> #include <script/solver.h> @@ -222,7 +223,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) fValid = false; break; } - COutPoint outpoint{TxidFromString(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())}; + COutPoint outpoint{Txid::FromHex(vinput[0].get_str()).value(), uint32_t(vinput[1].getInt<int>())}; mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); if (vinput.size() >= 4) { @@ -310,7 +311,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) fValid = false; break; } - COutPoint outpoint{TxidFromString(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())}; + COutPoint outpoint{Txid::FromHex(vinput[0].get_str()).value(), uint32_t(vinput[1].getInt<int>())}; mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); if (vinput.size() >= 4) { @@ -541,7 +542,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) // create a big transaction of 4500 inputs signed by the same key for(uint32_t ij = 0; ij < 4500; ij++) { uint32_t i = mtx.vin.size(); - COutPoint outpoint(TxidFromString("0000000000000000000000000000000000000000000000000000000000000100"), i); + COutPoint outpoint(Txid::FromHex("0000000000000000000000000000000000000000000000000000000000000100").value(), i); mtx.vin.resize(mtx.vin.size() + 1); mtx.vin[i].prevout = outpoint; @@ -578,9 +579,11 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) coins.emplace_back(std::move(coin)); } + SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES}; + for(uint32_t i = 0; i < mtx.vin.size(); i++) { std::vector<CScriptCheck> vChecks; - vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata); + vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, signature_cache, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata); control.Add(std::move(vChecks)); } @@ -1023,6 +1026,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].nValue = 239; CheckIsNotStandard(t, "dust"); } + + // Check anchor outputs + t.vout[0].scriptPubKey = CScript() << OP_1 << std::vector<unsigned char>{0x4e, 0x73}; + BOOST_CHECK(t.vout[0].scriptPubKey.IsPayToAnchor()); + t.vout[0].nValue = 240; + CheckIsStandard(t); + t.vout[0].nValue = 239; + CheckIsNotStandard(t, "dust"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index 478121cc6f..ca9dc5527d 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -43,13 +43,6 @@ inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outpu } return MakeTransactionRef(mtx); } - -// Create a Wtxid from a hex string -inline Wtxid WtxidFromString(std::string_view str) -{ - return Wtxid::FromUint256(uint256S(str.data())); -} - BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) { // Random real segwit transaction @@ -74,9 +67,9 @@ BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) CTransactionRef ptx_3{MakeTransactionRef(tx_3)}; // It's easy to see that wtxids are sorted in lexicographical order: - Wtxid wtxid_1{WtxidFromString("0x85cd1a31eb38f74ed5742ec9cb546712ab5aaf747de28a9168b53e846cbda17f")}; - Wtxid wtxid_2{WtxidFromString("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")}; - Wtxid wtxid_3{WtxidFromString("0xe065bac15f62bb4e761d761db928ddee65a47296b2b776785abb912cdec474e3")}; + Wtxid wtxid_1{Wtxid::FromHex("85cd1a31eb38f74ed5742ec9cb546712ab5aaf747de28a9168b53e846cbda17f").value()}; + Wtxid wtxid_2{Wtxid::FromHex("b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b").value()}; + Wtxid wtxid_3{Wtxid::FromHex("e065bac15f62bb4e761d761db928ddee65a47296b2b776785abb912cdec474e3").value()}; BOOST_CHECK_EQUAL(tx_1.GetWitnessHash(), wtxid_1); BOOST_CHECK_EQUAL(tx_2.GetWitnessHash(), wtxid_2); BOOST_CHECK_EQUAL(tx_3.GetWitnessHash(), wtxid_3); @@ -85,9 +78,9 @@ BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) BOOST_CHECK(wtxid_2.GetHex() < wtxid_3.GetHex()); // The txids are not (we want to test that sorting and hashing use wtxid, not txid): - Txid txid_1{TxidFromString("0xbd0f71c1d5e50589063e134fad22053cdae5ab2320db5bf5e540198b0b5a4e69")}; - Txid txid_2{TxidFromString("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")}; - Txid txid_3{TxidFromString("0xee707be5201160e32c4fc715bec227d1aeea5940fb4295605e7373edce3b1a93")}; + Txid txid_1{Txid::FromHex("bd0f71c1d5e50589063e134fad22053cdae5ab2320db5bf5e540198b0b5a4e69").value()}; + Txid txid_2{Txid::FromHex("b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b").value()}; + Txid txid_3{Txid::FromHex("ee707be5201160e32c4fc715bec227d1aeea5940fb4295605e7373edce3b1a93").value()}; BOOST_CHECK_EQUAL(tx_1.GetHash(), txid_1); BOOST_CHECK_EQUAL(tx_2.GetHash(), txid_2); BOOST_CHECK_EQUAL(tx_3.GetHash(), txid_3); @@ -303,7 +296,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup) // The parents can be in any order. FastRandomContext rng; - Shuffle(package.begin(), package.end(), rng); + std::shuffle(package.begin(), package.end(), rng); package.push_back(MakeTransactionRef(child)); PackageValidationState state; diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp index dc257a0d51..0ca70d2c7a 100644 --- a/src/test/txrequest_tests.cpp +++ b/src/test/txrequest_tests.cpp @@ -392,7 +392,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) // Determine the announcement order randomly. std::vector<NodeId> announce_order = request_order; - Shuffle(announce_order.begin(), announce_order.end(), g_insecure_rand_ctx); + std::shuffle(announce_order.begin(), announce_order.end(), g_insecure_rand_ctx); // Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and // within npref_peers. @@ -697,7 +697,7 @@ void TestInterleavedScenarios() builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); }); } // Randomly shuffle all those functions. - Shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx); + std::shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx); Runner runner; auto starttime = RandomTime1y(); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 78ef96a15d..af36a95693 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -5,6 +5,7 @@ #include <consensus/validation.h> #include <key.h> #include <random.h> +#include <script/sigcache.h> #include <script/sign.h> #include <script/signingprovider.h> #include <test/util/setup_common.h> @@ -16,12 +17,13 @@ struct Dersig100Setup : public TestChain100Setup { Dersig100Setup() - : TestChain100Setup{ChainType::REGTEST, {"-testactivationheight=dersig@102"}} {} + : TestChain100Setup{ChainType::REGTEST, {.extra_args = {"-testactivationheight=dersig@102"}}} {} }; bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, + ValidationCache& validation_cache, std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main); BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) @@ -118,7 +120,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, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { PrecomputedTransactionData txdata; @@ -140,7 +142,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail // WITNESS requires P2SH test_flags |= SCRIPT_VERIFY_P2SH; } - bool ret = CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, nullptr); + bool ret = CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, nullptr); // CheckInputScripts should succeed iff test_flags doesn't intersect with // failing_flags bool expected_return_value = !(test_flags & failing_flags); @@ -150,13 +152,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail if (ret && add_to_cache) { // Check that we get a cache hit if the tx was valid std::vector<CScriptCheck> scriptchecks; - BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks)); + BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, &scriptchecks)); BOOST_CHECK(scriptchecks.empty()); } else { // Check that we get script executions to check, if the transaction // was invalid, or we didn't add to cache. std::vector<CScriptCheck> scriptchecks; - BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks)); + BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); } } @@ -214,20 +216,20 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) TxValidationState state; PrecomputedTransactionData ptd_spend_tx; - BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); + BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, m_node.chainman->m_validation_cache, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector<CScriptCheck> scriptchecks; - BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks)); + BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, m_node.chainman->m_validation_cache, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1U); // Test that CheckInputScripts returns true iff DERSIG-enforcing flags are // not present. Don't add these checks to the cache, so that we can // test later that block validation works fine in the absence of cached // successes. - ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); } // And if we produce a block with this tx, it should be valid (DERSIG not @@ -253,7 +255,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end()); invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2; - ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); } // Test CHECKLOCKTIMEVERIFY @@ -276,13 +278,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; - ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); // Make it valid, and check again invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; TxValidationState state; PrecomputedTransactionData txdata; - BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); + BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, m_node.chainman->m_validation_cache, nullptr)); } // TEST CHECKSEQUENCEVERIFY @@ -304,13 +306,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; - ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); // Make it valid, and check again invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; TxValidationState state; PrecomputedTransactionData txdata; - BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); + BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, m_node.chainman->m_validation_cache, nullptr)); } // TODO: add tests for remaining script flags @@ -333,11 +335,11 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) UpdateInput(valid_with_witness_tx.vin[0], sigdata); // This should be valid under all script flags. - ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); // Remove the witness, and check that it is now invalid. valid_with_witness_tx.vin[0].scriptWitness.SetNull(); - ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); } { @@ -362,7 +364,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) } // This should be valid under all script flags - ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip()); + ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache); // Check that if the second input is invalid, but the first input is // valid, the transaction is not cached. @@ -372,12 +374,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) TxValidationState state; PrecomputedTransactionData txdata; // This transaction is now invalid under segwit, because of the second input. - BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr)); + BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, m_node.chainman->m_validation_cache, nullptr)); std::vector<CScriptCheck> scriptchecks; // Make sure this transaction was not cached (ie because the first // input was valid) - BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks)); + BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, m_node.chainman->m_validation_cache, &scriptchecks)); // Should get 2 script checks back -- caching is on a whole-transaction basis. BOOST_CHECK_EQUAL(scriptchecks.size(), 2U); } diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index b7892a2139..2ba3227174 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -6,12 +6,15 @@ #include <streams.h> #include <test/util/setup_common.h> #include <uint256.h> +#include <util/strencodings.h> +#include <util/transaction_identifier.h> #include <boost/test/unit_test.hpp> #include <iomanip> #include <sstream> #include <string> +#include <string_view> #include <vector> BOOST_AUTO_TEST_SUITE(uint256_tests) @@ -58,69 +61,68 @@ static std::string ArrayToString(const unsigned char A[], unsigned int width) return Stream.str(); } -inline uint160 uint160S(const char *str) +// Takes hex string in reverse byte order. +inline uint160 uint160S(std::string_view str) { uint160 rv; - rv.SetHex(str); - return rv; -} -inline uint160 uint160S(const std::string& str) -{ - uint160 rv; - rv.SetHex(str); + rv.SetHexDeprecated(str); return rv; } BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality { - BOOST_CHECK(1 == 0+1); // constructor uint256(vector<char>): - BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32)); - BOOST_CHECK(R1S.ToString() == ArrayToString(R1Array,20)); - BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32)); - BOOST_CHECK(R2S.ToString() == ArrayToString(R2Array,20)); - BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32)); - BOOST_CHECK(ZeroS.ToString() == ArrayToString(ZeroArray,20)); - BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray,32)); - BOOST_CHECK(OneS.ToString() == ArrayToString(OneArray,20)); - BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray,32)); - BOOST_CHECK(MaxS.ToString() == ArrayToString(MaxArray,20)); - BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray,32)); - BOOST_CHECK(OneS.ToString() != ArrayToString(ZeroArray,20)); + BOOST_CHECK_EQUAL(R1L.ToString(), ArrayToString(R1Array,32)); + BOOST_CHECK_EQUAL(R1S.ToString(), ArrayToString(R1Array,20)); + BOOST_CHECK_EQUAL(R2L.ToString(), ArrayToString(R2Array,32)); + BOOST_CHECK_EQUAL(R2S.ToString(), ArrayToString(R2Array,20)); + BOOST_CHECK_EQUAL(ZeroL.ToString(), ArrayToString(ZeroArray,32)); + BOOST_CHECK_EQUAL(ZeroS.ToString(), ArrayToString(ZeroArray,20)); + BOOST_CHECK_EQUAL(OneL.ToString(), ArrayToString(OneArray,32)); + BOOST_CHECK_EQUAL(OneS.ToString(), ArrayToString(OneArray,20)); + BOOST_CHECK_EQUAL(MaxL.ToString(), ArrayToString(MaxArray,32)); + BOOST_CHECK_EQUAL(MaxS.ToString(), ArrayToString(MaxArray,20)); + BOOST_CHECK_NE(OneL.ToString(), ArrayToString(ZeroArray,32)); + BOOST_CHECK_NE(OneS.ToString(), ArrayToString(ZeroArray,20)); // == and != - BOOST_CHECK(R1L != R2L && R1S != R2S); - BOOST_CHECK(ZeroL != OneL && ZeroS != OneS); - BOOST_CHECK(OneL != ZeroL && OneS != ZeroS); - BOOST_CHECK(MaxL != ZeroL && MaxS != ZeroS); + BOOST_CHECK_NE(R1L, R2L); BOOST_CHECK_NE(R1S, R2S); + BOOST_CHECK_NE(ZeroL, OneL); BOOST_CHECK_NE(ZeroS, OneS); + BOOST_CHECK_NE(OneL, ZeroL); BOOST_CHECK_NE(OneS, ZeroS); + BOOST_CHECK_NE(MaxL, ZeroL); BOOST_CHECK_NE(MaxS, ZeroS); // String Constructor and Copy Constructor - BOOST_CHECK(uint256S("0x"+R1L.ToString()) == R1L); - BOOST_CHECK(uint256S("0x"+R2L.ToString()) == R2L); - BOOST_CHECK(uint256S("0x"+ZeroL.ToString()) == ZeroL); - BOOST_CHECK(uint256S("0x"+OneL.ToString()) == OneL); - BOOST_CHECK(uint256S("0x"+MaxL.ToString()) == MaxL); - BOOST_CHECK(uint256S(R1L.ToString()) == R1L); - BOOST_CHECK(uint256S(" 0x"+R1L.ToString()+" ") == R1L); - BOOST_CHECK(uint256S("") == ZeroL); - BOOST_CHECK(R1L == uint256S(R1ArrayHex)); - BOOST_CHECK(uint256(R1L) == R1L); - BOOST_CHECK(uint256(ZeroL) == ZeroL); - BOOST_CHECK(uint256(OneL) == OneL); - - BOOST_CHECK(uint160S("0x"+R1S.ToString()) == R1S); - BOOST_CHECK(uint160S("0x"+R2S.ToString()) == R2S); - BOOST_CHECK(uint160S("0x"+ZeroS.ToString()) == ZeroS); - BOOST_CHECK(uint160S("0x"+OneS.ToString()) == OneS); - BOOST_CHECK(uint160S("0x"+MaxS.ToString()) == MaxS); - BOOST_CHECK(uint160S(R1S.ToString()) == R1S); - BOOST_CHECK(uint160S(" 0x"+R1S.ToString()+" ") == R1S); - BOOST_CHECK(uint160S("") == ZeroS); - BOOST_CHECK(R1S == uint160S(R1ArrayHex)); - - BOOST_CHECK(uint160(R1S) == R1S); - BOOST_CHECK(uint160(ZeroS) == ZeroS); - BOOST_CHECK(uint160(OneS) == OneS); + BOOST_CHECK_EQUAL(uint256S("0x"+R1L.ToString()), R1L); + BOOST_CHECK_EQUAL(uint256S("0x"+R2L.ToString()), R2L); + BOOST_CHECK_EQUAL(uint256S("0x"+ZeroL.ToString()), ZeroL); + BOOST_CHECK_EQUAL(uint256S("0x"+OneL.ToString()), OneL); + BOOST_CHECK_EQUAL(uint256S("0x"+MaxL.ToString()), MaxL); + BOOST_CHECK_EQUAL(uint256S(R1L.ToString()), R1L); + BOOST_CHECK_EQUAL(uint256S(" 0x"+R1L.ToString()+" "), R1L); + BOOST_CHECK_EQUAL(uint256S(" 0x"+R1L.ToString()+"-trash;%^& "), R1L); + BOOST_CHECK_EQUAL(uint256S("\t \n \n \f\n\r\t\v\t 0x"+R1L.ToString()+" \t \n \n \f\n\r\t\v\t "), R1L); + BOOST_CHECK_EQUAL(uint256S(""), ZeroL); + BOOST_CHECK_EQUAL(uint256S("1"), OneL); + BOOST_CHECK_EQUAL(R1L, uint256S(R1ArrayHex)); + BOOST_CHECK_EQUAL(uint256(R1L), R1L); + BOOST_CHECK_EQUAL(uint256(ZeroL), ZeroL); + BOOST_CHECK_EQUAL(uint256(OneL), OneL); + + BOOST_CHECK_EQUAL(uint160S("0x"+R1S.ToString()), R1S); + BOOST_CHECK_EQUAL(uint160S("0x"+R2S.ToString()), R2S); + BOOST_CHECK_EQUAL(uint160S("0x"+ZeroS.ToString()), ZeroS); + BOOST_CHECK_EQUAL(uint160S("0x"+OneS.ToString()), OneS); + BOOST_CHECK_EQUAL(uint160S("0x"+MaxS.ToString()), MaxS); + BOOST_CHECK_EQUAL(uint160S(R1S.ToString()), R1S); + BOOST_CHECK_EQUAL(uint160S(" 0x"+R1S.ToString()+" "), R1S); + BOOST_CHECK_EQUAL(uint160S(" 0x"+R1S.ToString()+"-trash;%^& "), R1S); + BOOST_CHECK_EQUAL(uint160S(" \t \n \n \f\n\r\t\v\t 0x"+R1S.ToString()+" \t \n \n \f\n\r\t\v\t"), R1S); + BOOST_CHECK_EQUAL(uint160S(""), ZeroS); + BOOST_CHECK_EQUAL(R1S, uint160S(R1ArrayHex)); + + BOOST_CHECK_EQUAL(uint160(R1S), R1S); + BOOST_CHECK_EQUAL(uint160(ZeroS), ZeroS); + BOOST_CHECK_EQUAL(uint160(OneS), OneS); } BOOST_AUTO_TEST_CASE( comparison ) // <= >= < > @@ -129,140 +131,153 @@ BOOST_AUTO_TEST_CASE( comparison ) // <= >= < > for (int i = 255; i >= 0; --i) { uint256 TmpL; *(TmpL.begin() + (i>>3)) |= 1<<(7-(i&7)); - BOOST_CHECK( LastL < TmpL ); + BOOST_CHECK_LT(LastL, TmpL); LastL = TmpL; } - BOOST_CHECK( ZeroL < R1L ); - BOOST_CHECK( R2L < R1L ); - BOOST_CHECK( ZeroL < OneL ); - BOOST_CHECK( OneL < MaxL ); - BOOST_CHECK( R1L < MaxL ); - BOOST_CHECK( R2L < MaxL ); + BOOST_CHECK_LT(ZeroL, R1L); + BOOST_CHECK_LT(R2L, R1L); + BOOST_CHECK_LT(ZeroL, OneL); + BOOST_CHECK_LT(OneL, MaxL); + BOOST_CHECK_LT(R1L, MaxL); + BOOST_CHECK_LT(R2L, MaxL); uint160 LastS; for (int i = 159; i >= 0; --i) { uint160 TmpS; *(TmpS.begin() + (i>>3)) |= 1<<(7-(i&7)); - BOOST_CHECK( LastS < TmpS ); + BOOST_CHECK_LT(LastS, TmpS); LastS = TmpS; } - BOOST_CHECK( ZeroS < R1S ); - BOOST_CHECK( R2S < R1S ); - BOOST_CHECK( ZeroS < OneS ); - BOOST_CHECK( OneS < MaxS ); - BOOST_CHECK( R1S < MaxS ); - BOOST_CHECK( R2S < MaxS ); + BOOST_CHECK_LT(ZeroS, R1S); + BOOST_CHECK_LT(R2S, R1S); + BOOST_CHECK_LT(ZeroS, OneS); + BOOST_CHECK_LT(OneS, MaxS); + BOOST_CHECK_LT(R1S, MaxS); + BOOST_CHECK_LT(R2S, MaxS); + + // Non-arithmetic uint256s compare from the beginning of their inner arrays: + BOOST_CHECK_LT(R2L, R1L); + // Ensure first element comparisons give the same order as above: + BOOST_CHECK_LT(*R2L.begin(), *R1L.begin()); + // Ensure last element comparisons give a different result (swapped params): + BOOST_CHECK_LT(*(R1L.end()-1), *(R2L.end()-1)); + // Hex strings represent reverse-encoded bytes, with lexicographic ordering: + BOOST_CHECK_LT(uint256{"1000000000000000000000000000000000000000000000000000000000000000"}, + uint256{"0000000000000000000000000000000000000000000000000000000000000001"}); } -BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 GetSerializeSize, Serialize, Unserialize +BOOST_AUTO_TEST_CASE(methods) // GetHex SetHexDeprecated FromHex begin() end() size() GetLow64 GetSerializeSize, Serialize, Unserialize { - BOOST_CHECK(R1L.GetHex() == R1L.ToString()); - BOOST_CHECK(R2L.GetHex() == R2L.ToString()); - BOOST_CHECK(OneL.GetHex() == OneL.ToString()); - BOOST_CHECK(MaxL.GetHex() == MaxL.ToString()); + BOOST_CHECK_EQUAL(R1L.GetHex(), R1L.ToString()); + BOOST_CHECK_EQUAL(R2L.GetHex(), R2L.ToString()); + BOOST_CHECK_EQUAL(OneL.GetHex(), OneL.ToString()); + BOOST_CHECK_EQUAL(MaxL.GetHex(), MaxL.ToString()); uint256 TmpL(R1L); - BOOST_CHECK(TmpL == R1L); - TmpL.SetHex(R2L.ToString()); BOOST_CHECK(TmpL == R2L); - TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == uint256()); - - TmpL.SetHex(R1L.ToString()); - BOOST_CHECK(memcmp(R1L.begin(), R1Array, 32)==0); - BOOST_CHECK(memcmp(TmpL.begin(), R1Array, 32)==0); - BOOST_CHECK(memcmp(R2L.begin(), R2Array, 32)==0); - BOOST_CHECK(memcmp(ZeroL.begin(), ZeroArray, 32)==0); - BOOST_CHECK(memcmp(OneL.begin(), OneArray, 32)==0); - BOOST_CHECK(R1L.size() == sizeof(R1L)); - BOOST_CHECK(sizeof(R1L) == 32); - BOOST_CHECK(R1L.size() == 32); - BOOST_CHECK(R2L.size() == 32); - BOOST_CHECK(ZeroL.size() == 32); - BOOST_CHECK(MaxL.size() == 32); - BOOST_CHECK(R1L.begin() + 32 == R1L.end()); - BOOST_CHECK(R2L.begin() + 32 == R2L.end()); - BOOST_CHECK(OneL.begin() + 32 == OneL.end()); - BOOST_CHECK(MaxL.begin() + 32 == MaxL.end()); - BOOST_CHECK(TmpL.begin() + 32 == TmpL.end()); - BOOST_CHECK(GetSerializeSize(R1L) == 32); - BOOST_CHECK(GetSerializeSize(ZeroL) == 32); + BOOST_CHECK_EQUAL(TmpL, R1L); + // Verify previous values don't persist when setting to truncated string. + TmpL.SetHexDeprecated("21"); + BOOST_CHECK_EQUAL(TmpL.ToString(), "0000000000000000000000000000000000000000000000000000000000000021"); + BOOST_CHECK_EQUAL(uint256::FromHex(R2L.ToString()).value(), R2L); + BOOST_CHECK_EQUAL(uint256::FromHex(ZeroL.ToString()).value(), uint256()); + + TmpL = uint256::FromHex(R1L.ToString()).value(); + BOOST_CHECK_EQUAL_COLLECTIONS(R1L.begin(), R1L.end(), R1Array, R1Array + uint256::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(TmpL.begin(), TmpL.end(), R1Array, R1Array + uint256::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(R2L.begin(), R2L.end(), R2Array, R2Array + uint256::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(ZeroL.begin(), ZeroL.end(), ZeroArray, ZeroArray + uint256::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(OneL.begin(), OneL.end(), OneArray, OneArray + uint256::size()); + BOOST_CHECK_EQUAL(R1L.size(), sizeof(R1L)); + BOOST_CHECK_EQUAL(sizeof(R1L), 32); + BOOST_CHECK_EQUAL(R1L.size(), 32); + BOOST_CHECK_EQUAL(R2L.size(), 32); + BOOST_CHECK_EQUAL(ZeroL.size(), 32); + BOOST_CHECK_EQUAL(MaxL.size(), 32); + BOOST_CHECK_EQUAL(R1L.begin() + 32, R1L.end()); + BOOST_CHECK_EQUAL(R2L.begin() + 32, R2L.end()); + BOOST_CHECK_EQUAL(OneL.begin() + 32, OneL.end()); + BOOST_CHECK_EQUAL(MaxL.begin() + 32, MaxL.end()); + BOOST_CHECK_EQUAL(TmpL.begin() + 32, TmpL.end()); + BOOST_CHECK_EQUAL(GetSerializeSize(R1L), 32); + BOOST_CHECK_EQUAL(GetSerializeSize(ZeroL), 32); DataStream ss{}; ss << R1L; - BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32)); + BOOST_CHECK_EQUAL(ss.str(), std::string(R1Array,R1Array+32)); ss >> TmpL; - BOOST_CHECK(R1L == TmpL); + BOOST_CHECK_EQUAL(R1L, TmpL); ss.clear(); ss << ZeroL; - BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+32)); + BOOST_CHECK_EQUAL(ss.str(), std::string(ZeroArray,ZeroArray+32)); ss >> TmpL; - BOOST_CHECK(ZeroL == TmpL); + BOOST_CHECK_EQUAL(ZeroL, TmpL); ss.clear(); ss << MaxL; - BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+32)); + BOOST_CHECK_EQUAL(ss.str(), std::string(MaxArray,MaxArray+32)); ss >> TmpL; - BOOST_CHECK(MaxL == TmpL); + BOOST_CHECK_EQUAL(MaxL, TmpL); ss.clear(); - BOOST_CHECK(R1S.GetHex() == R1S.ToString()); - BOOST_CHECK(R2S.GetHex() == R2S.ToString()); - BOOST_CHECK(OneS.GetHex() == OneS.ToString()); - BOOST_CHECK(MaxS.GetHex() == MaxS.ToString()); + BOOST_CHECK_EQUAL(R1S.GetHex(), R1S.ToString()); + BOOST_CHECK_EQUAL(R2S.GetHex(), R2S.ToString()); + BOOST_CHECK_EQUAL(OneS.GetHex(), OneS.ToString()); + BOOST_CHECK_EQUAL(MaxS.GetHex(), MaxS.ToString()); uint160 TmpS(R1S); - BOOST_CHECK(TmpS == R1S); - TmpS.SetHex(R2S.ToString()); BOOST_CHECK(TmpS == R2S); - TmpS.SetHex(ZeroS.ToString()); BOOST_CHECK(TmpS == uint160()); - - TmpS.SetHex(R1S.ToString()); - BOOST_CHECK(memcmp(R1S.begin(), R1Array, 20)==0); - BOOST_CHECK(memcmp(TmpS.begin(), R1Array, 20)==0); - BOOST_CHECK(memcmp(R2S.begin(), R2Array, 20)==0); - BOOST_CHECK(memcmp(ZeroS.begin(), ZeroArray, 20)==0); - BOOST_CHECK(memcmp(OneS.begin(), OneArray, 20)==0); - BOOST_CHECK(R1S.size() == sizeof(R1S)); - BOOST_CHECK(sizeof(R1S) == 20); - BOOST_CHECK(R1S.size() == 20); - BOOST_CHECK(R2S.size() == 20); - BOOST_CHECK(ZeroS.size() == 20); - BOOST_CHECK(MaxS.size() == 20); - BOOST_CHECK(R1S.begin() + 20 == R1S.end()); - BOOST_CHECK(R2S.begin() + 20 == R2S.end()); - BOOST_CHECK(OneS.begin() + 20 == OneS.end()); - BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); - BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); - BOOST_CHECK(GetSerializeSize(R1S) == 20); - BOOST_CHECK(GetSerializeSize(ZeroS) == 20); + BOOST_CHECK_EQUAL(TmpS, R1S); + BOOST_CHECK_EQUAL(uint160::FromHex(R2S.ToString()).value(), R2S); + BOOST_CHECK_EQUAL(uint160::FromHex(ZeroS.ToString()).value(), uint160()); + + TmpS = uint160::FromHex(R1S.ToString()).value(); + BOOST_CHECK_EQUAL_COLLECTIONS(R1S.begin(), R1S.end(), R1Array, R1Array + uint160::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(TmpS.begin(), TmpS.end(), R1Array, R1Array + uint160::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(R2S.begin(), R2S.end(), R2Array, R2Array + uint160::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(ZeroS.begin(), ZeroS.end(), ZeroArray, ZeroArray + uint160::size()); + BOOST_CHECK_EQUAL_COLLECTIONS(OneS.begin(), OneS.end(), OneArray, OneArray + uint160::size()); + BOOST_CHECK_EQUAL(R1S.size(), sizeof(R1S)); + BOOST_CHECK_EQUAL(sizeof(R1S), 20); + BOOST_CHECK_EQUAL(R1S.size(), 20); + BOOST_CHECK_EQUAL(R2S.size(), 20); + BOOST_CHECK_EQUAL(ZeroS.size(), 20); + BOOST_CHECK_EQUAL(MaxS.size(), 20); + BOOST_CHECK_EQUAL(R1S.begin() + 20, R1S.end()); + BOOST_CHECK_EQUAL(R2S.begin() + 20, R2S.end()); + BOOST_CHECK_EQUAL(OneS.begin() + 20, OneS.end()); + BOOST_CHECK_EQUAL(MaxS.begin() + 20, MaxS.end()); + BOOST_CHECK_EQUAL(TmpS.begin() + 20, TmpS.end()); + BOOST_CHECK_EQUAL(GetSerializeSize(R1S), 20); + BOOST_CHECK_EQUAL(GetSerializeSize(ZeroS), 20); ss << R1S; - BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20)); + BOOST_CHECK_EQUAL(ss.str(), std::string(R1Array,R1Array+20)); ss >> TmpS; - BOOST_CHECK(R1S == TmpS); + BOOST_CHECK_EQUAL(R1S, TmpS); ss.clear(); ss << ZeroS; - BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+20)); + BOOST_CHECK_EQUAL(ss.str(), std::string(ZeroArray,ZeroArray+20)); ss >> TmpS; - BOOST_CHECK(ZeroS == TmpS); + BOOST_CHECK_EQUAL(ZeroS, TmpS); ss.clear(); ss << MaxS; - BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+20)); + BOOST_CHECK_EQUAL(ss.str(), std::string(MaxArray,MaxArray+20)); ss >> TmpS; - BOOST_CHECK(MaxS == TmpS); + BOOST_CHECK_EQUAL(MaxS, TmpS); ss.clear(); } BOOST_AUTO_TEST_CASE( conversion ) { - BOOST_CHECK(ArithToUint256(UintToArith256(ZeroL)) == ZeroL); - BOOST_CHECK(ArithToUint256(UintToArith256(OneL)) == OneL); - BOOST_CHECK(ArithToUint256(UintToArith256(R1L)) == R1L); - BOOST_CHECK(ArithToUint256(UintToArith256(R2L)) == R2L); - BOOST_CHECK(UintToArith256(ZeroL) == 0); - BOOST_CHECK(UintToArith256(OneL) == 1); - BOOST_CHECK(ArithToUint256(0) == ZeroL); - BOOST_CHECK(ArithToUint256(1) == OneL); - BOOST_CHECK(arith_uint256(UintToArith256(uint256S(R1L.GetHex()))) == UintToArith256(R1L)); - BOOST_CHECK(arith_uint256(UintToArith256(uint256S(R2L.GetHex()))) == UintToArith256(R2L)); - BOOST_CHECK(R1L.GetHex() == UintToArith256(R1L).GetHex()); - BOOST_CHECK(R2L.GetHex() == UintToArith256(R2L).GetHex()); + BOOST_CHECK_EQUAL(ArithToUint256(UintToArith256(ZeroL)), ZeroL); + BOOST_CHECK_EQUAL(ArithToUint256(UintToArith256(OneL)), OneL); + BOOST_CHECK_EQUAL(ArithToUint256(UintToArith256(R1L)), R1L); + BOOST_CHECK_EQUAL(ArithToUint256(UintToArith256(R2L)), R2L); + BOOST_CHECK_EQUAL(UintToArith256(ZeroL), 0); + BOOST_CHECK_EQUAL(UintToArith256(OneL), 1); + BOOST_CHECK_EQUAL(ArithToUint256(0), ZeroL); + BOOST_CHECK_EQUAL(ArithToUint256(1), OneL); + BOOST_CHECK_EQUAL(arith_uint256(UintToArith256(uint256S(R1L.GetHex()))), UintToArith256(R1L)); + BOOST_CHECK_EQUAL(arith_uint256(UintToArith256(uint256S(R2L.GetHex()))), UintToArith256(R2L)); + BOOST_CHECK_EQUAL(R1L.GetHex(), UintToArith256(R1L).GetHex()); + BOOST_CHECK_EQUAL(R2L.GetHex(), UintToArith256(R2L).GetHex()); } BOOST_AUTO_TEST_CASE( operator_with_self ) @@ -285,13 +300,13 @@ BOOST_AUTO_TEST_CASE( operator_with_self ) #endif arith_uint256 v = UintToArith256(uint256S("02")); v *= v; - BOOST_CHECK(v == UintToArith256(uint256S("04"))); + BOOST_CHECK_EQUAL(v, UintToArith256(uint256S("04"))); v /= v; - BOOST_CHECK(v == UintToArith256(uint256S("01"))); + BOOST_CHECK_EQUAL(v, UintToArith256(uint256S("01"))); v += v; - BOOST_CHECK(v == UintToArith256(uint256S("02"))); + BOOST_CHECK_EQUAL(v, UintToArith256(uint256S("02"))); v -= v; - BOOST_CHECK(v == UintToArith256(uint256S("0"))); + BOOST_CHECK_EQUAL(v, UintToArith256(uint256S("0"))); #if defined(__clang__) # pragma clang diagnostic pop #endif @@ -302,7 +317,7 @@ BOOST_AUTO_TEST_CASE(parse) { std::string s_12{"0000000000000000000000000000000000000000000000000000000000000012"}; BOOST_CHECK_EQUAL(uint256S("12\0").GetHex(), s_12); - BOOST_CHECK_EQUAL(uint256S(std::string{"12\0", 3}).GetHex(), s_12); + BOOST_CHECK_EQUAL(uint256S(std::string_view{"12\0", 3}).GetHex(), s_12); BOOST_CHECK_EQUAL(uint256S("0x12").GetHex(), s_12); BOOST_CHECK_EQUAL(uint256S(" 0x12").GetHex(), s_12); BOOST_CHECK_EQUAL(uint256S(" 12").GetHex(), s_12); @@ -310,7 +325,7 @@ BOOST_AUTO_TEST_CASE(parse) { std::string s_1{uint256::ONE.GetHex()}; BOOST_CHECK_EQUAL(uint256S("1\0").GetHex(), s_1); - BOOST_CHECK_EQUAL(uint256S(std::string{"1\0", 2}).GetHex(), s_1); + BOOST_CHECK_EQUAL(uint256S(std::string_view{"1\0", 2}).GetHex(), s_1); BOOST_CHECK_EQUAL(uint256S("0x1").GetHex(), s_1); BOOST_CHECK_EQUAL(uint256S(" 0x1").GetHex(), s_1); BOOST_CHECK_EQUAL(uint256S(" 1").GetHex(), s_1); @@ -318,17 +333,77 @@ BOOST_AUTO_TEST_CASE(parse) { std::string s_0{uint256::ZERO.GetHex()}; BOOST_CHECK_EQUAL(uint256S("\0").GetHex(), s_0); - BOOST_CHECK_EQUAL(uint256S(std::string{"\0", 1}).GetHex(), s_0); + BOOST_CHECK_EQUAL(uint256S(std::string_view{"\0", 1}).GetHex(), s_0); BOOST_CHECK_EQUAL(uint256S("0x").GetHex(), s_0); BOOST_CHECK_EQUAL(uint256S(" 0x").GetHex(), s_0); BOOST_CHECK_EQUAL(uint256S(" ").GetHex(), s_0); } } +/** + * Implemented as a templated function so it can be reused by other classes that have a FromHex() + * method that wraps base_blob::FromHex(), such as transaction_identifier::FromHex(). + */ +template <typename T> +void TestFromHex() +{ + constexpr unsigned int num_chars{T::size() * 2}; + static_assert(num_chars <= 64); // this test needs to be modified to allow for more than 64 hex chars + const std::string valid_64char_input{"0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF"}; + const auto valid_input{valid_64char_input.substr(0, num_chars)}; + { + // check that lower and upper case hex characters are accepted + auto valid_result{T::FromHex(valid_input)}; + BOOST_REQUIRE(valid_result); + BOOST_CHECK_EQUAL(valid_result->ToString(), ToLower(valid_input)); + } + { + // check that only strings of size num_chars are accepted + BOOST_CHECK(!T::FromHex("")); + BOOST_CHECK(!T::FromHex("0")); + BOOST_CHECK(!T::FromHex(valid_input.substr(0, num_chars / 2))); + BOOST_CHECK(!T::FromHex(valid_input.substr(0, num_chars - 1))); + BOOST_CHECK(!T::FromHex(valid_input + "0")); + } + { + // check that non-hex characters are not accepted + std::string invalid_chars{R"( !"#$%&'()*+,-./:;<=>?@GHIJKLMNOPQRSTUVWXYZ[\]^_`ghijklmnopqrstuvwxyz{|}~)"}; + for (auto c : invalid_chars) { + BOOST_CHECK(!T::FromHex(valid_input.substr(0, num_chars - 1) + c)); + } + // 0x prefixes are invalid + std::string invalid_prefix{"0x" + valid_input}; + BOOST_CHECK(!T::FromHex(std::string_view(invalid_prefix.data(), num_chars))); + BOOST_CHECK(!T::FromHex(invalid_prefix)); + } + { + // check that string_view length is respected + std::string chars_68{valid_64char_input + "0123"}; + BOOST_CHECK_EQUAL(T::FromHex(std::string_view(chars_68.data(), num_chars)).value().ToString(), ToLower(valid_input)); + BOOST_CHECK(!T::FromHex(std::string_view(chars_68.data(), num_chars - 1))); // too short + BOOST_CHECK(!T::FromHex(std::string_view(chars_68.data(), num_chars + 1))); // too long + } +} + +BOOST_AUTO_TEST_CASE(from_hex) +{ + TestFromHex<uint160>(); + TestFromHex<uint256>(); + TestFromHex<Txid>(); + TestFromHex<Wtxid>(); +} + BOOST_AUTO_TEST_CASE( check_ONE ) { - uint256 one = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + uint256 one = uint256{"0000000000000000000000000000000000000000000000000000000000000001"}; BOOST_CHECK_EQUAL(one, uint256::ONE); } +BOOST_AUTO_TEST_CASE(FromHex_vs_uint256) +{ + auto runtime_uint{uint256::FromHex("4A5E1E4BAAB89F3A32518A88C31BC87F618f76673e2cc77ab2127b7afdeda33b").value()}; + constexpr uint256 consteval_uint{ "4a5e1e4baab89f3a32518a88c31bc87f618F76673E2CC77AB2127B7AFDEDA33B"}; + BOOST_CHECK_EQUAL(consteval_uint, runtime_uint); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index a4636365ca..e604b44c16 100644 --- a/src/test/util/chainstate.h +++ b/src/test/util/chainstate.h @@ -99,7 +99,7 @@ CreateAndActivateUTXOSnapshot( assert(pindex->IsValid(BlockStatus::BLOCK_VALID_TREE)); pindex->nStatus = BlockStatus::BLOCK_VALID_TREE; pindex->nTx = 0; - pindex->nChainTx = 0; + pindex->m_chain_tx_count = 0; pindex->nSequenceId = 0; pindex = pindex->pprev; } diff --git a/src/test/util/cluster_linearize.h b/src/test/util/cluster_linearize.h new file mode 100644 index 0000000000..508a08133c --- /dev/null +++ b/src/test/util/cluster_linearize.h @@ -0,0 +1,353 @@ +// Copyright (c) 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_CLUSTER_LINEARIZE_H +#define BITCOIN_TEST_UTIL_CLUSTER_LINEARIZE_H + +#include <cluster_linearize.h> +#include <serialize.h> +#include <span.h> +#include <streams.h> +#include <util/bitset.h> +#include <util/feefrac.h> + +#include <stdint.h> +#include <numeric> +#include <vector> +#include <utility> + +namespace { + +using namespace cluster_linearize; + +using TestBitSet = BitSet<32>; + +/** Check if a graph is acyclic. */ +template<typename SetType> +bool IsAcyclic(const DepGraph<SetType>& depgraph) noexcept +{ + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + if ((depgraph.Ancestors(i) & depgraph.Descendants(i)) != SetType::Singleton(i)) { + return false; + } + } + return true; +} + +/** A formatter for a bespoke serialization for acyclic DepGraph objects. + * + * The serialization format outputs information about transactions in a topological order (parents + * before children), together with position information so transactions can be moved back to their + * correct position on deserialization. + * + * - For each transaction t in the DepGraph (in some topological order); + * - The size: VARINT(t.size), which cannot be 0. + * - The fee: VARINT(SignedToUnsigned(t.fee)), see below for SignedToUnsigned. + * - For each direct dependency: + * - VARINT(skip) + * - The position of t in the cluster: VARINT(skip) + * - The end of the graph: VARINT(0) + * + * The list of skip values encodes the dependencies of t, as well as its position in the cluster. + * Each skip value is the number of possibilities that were available, but were not taken. These + * possibilities are, in order: + * - For each previous transaction in the graph, in reverse serialization order, whether it is a + * direct parent of t (but excluding transactions which are already implied to be dependencies + * by parent relations that were serialized before it). + * - The various insertion positions in the cluster, from the very end of the cluster, to the + * front. + * + * Let's say you have a 7-transaction cluster, consisting of transactions F,A,C,B,G,E,D, but + * serialized in order A,B,C,D,E,F,G, because that happens to be a topological ordering. By the + * time G gets serialized, what has been serialized already represents the cluster F,A,C,B,E,D (in + * that order). G has B and E as direct parents, and E depends on C. + * + * In this case, the possibilities are, in order: + * - [ ] the dependency G->F + * - [X] the dependency G->E + * - [ ] the dependency G->D + * - [X] the dependency G->B + * - [ ] the dependency G->A + * - [ ] put G at the end of the cluster + * - [ ] put G before D + * - [X] put G before E + * - [ ] put G before B + * - [ ] put G before C + * - [ ] put G before A + * - [ ] put G before F + * + * The skip values in this case are 1 (G->F), 1 (G->D), 3 (G->A, G at end, G before D). No skip + * after 3 is needed (or permitted), because there can only be one position for G. Also note that + * G->C is not included in the list of possibilities, as it is implied by the included G->E and + * E->C that came before it. On deserialization, if the last skip value was 8 or larger (putting + * G before the beginning of the cluster), it is interpreted as wrapping around back to the end. + * + * + * Rationale: + * - Why VARINTs? They are flexible enough to represent large numbers where needed, but more + * compact for smaller numbers. The serialization format is designed so that simple structures + * involve smaller numbers, so smaller size maps to simpler graphs. + * - Why use SignedToUnsigned? It results in small unsigned values for signed values with small + * absolute value. This way we can encode negative fees in graphs, but still let small negative + * numbers have small encodings. + * - Why are the parents emitted in reverse order compared to the transactions themselves? This + * naturally lets us skip parents-of-parents, as they will be reflected as implied dependencies. + * - Why encode skip values and not a bitmask to convey the list positions? It turns out that the + * most complex graphs (in terms of linearization complexity) are ones with ~1 dependency per + * transaction. The current encoding uses ~1 byte per transaction for dependencies in this case, + * while a bitmask would require ~N/2 bits per transaction. + */ + +struct DepGraphFormatter +{ + /** Convert x>=0 to 2x (even), x<0 to -2x-1 (odd). */ + static uint64_t SignedToUnsigned(int64_t x) noexcept + { + if (x < 0) { + return 2 * uint64_t(-(x + 1)) + 1; + } else { + return 2 * uint64_t(x); + } + } + + /** Convert even x to x/2 (>=0), odd x to -(x/2)-1 (<0). */ + static int64_t UnsignedToSigned(uint64_t x) noexcept + { + if (x & 1) { + return -int64_t(x / 2) - 1; + } else { + return int64_t(x / 2); + } + } + + template <typename Stream, typename SetType> + static void Ser(Stream& s, const DepGraph<SetType>& depgraph) + { + /** Construct a topological order to serialize the transactions in. */ + std::vector<ClusterIndex> topo_order(depgraph.TxCount()); + std::iota(topo_order.begin(), topo_order.end(), ClusterIndex{0}); + std::sort(topo_order.begin(), topo_order.end(), [&](ClusterIndex a, ClusterIndex b) { + auto anc_a = depgraph.Ancestors(a).Count(), anc_b = depgraph.Ancestors(b).Count(); + if (anc_a != anc_b) return anc_a < anc_b; + return a < b; + }); + + /** Which transactions the deserializer already knows when it has deserialized what has + * been serialized here so far, and in what order. */ + std::vector<ClusterIndex> rebuilt_order; + rebuilt_order.reserve(depgraph.TxCount()); + + // Loop over the transactions in topological order. + for (ClusterIndex topo_idx = 0; topo_idx < topo_order.size(); ++topo_idx) { + /** Which depgraph index we are currently writing. */ + ClusterIndex idx = topo_order[topo_idx]; + // Write size, which must be larger than 0. + s << VARINT_MODE(depgraph.FeeRate(idx).size, VarIntMode::NONNEGATIVE_SIGNED); + // Write fee, encoded as an unsigned varint (odd=negative, even=non-negative). + s << VARINT(SignedToUnsigned(depgraph.FeeRate(idx).fee)); + // Write dependency information. + SetType written_parents; + uint64_t diff = 0; //!< How many potential parent/child relations we have skipped over. + for (ClusterIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { + /** Which depgraph index we are currently considering as parent of idx. */ + ClusterIndex dep_idx = topo_order[topo_idx - 1 - dep_dist]; + // Ignore transactions which are already known to be ancestors. + if (depgraph.Descendants(dep_idx).Overlaps(written_parents)) continue; + if (depgraph.Ancestors(idx)[dep_idx]) { + // When an actual parent is encounted, encode how many non-parents were skipped + // before it. + s << VARINT(diff); + diff = 0; + written_parents.Set(dep_idx); + } else { + // When a non-parent is encountered, increment the skip counter. + ++diff; + } + } + // Write position information. + ClusterIndex insert_distance = 0; + while (insert_distance < rebuilt_order.size()) { + // Loop to find how far from the end in rebuilt_order to insert. + if (idx > *(rebuilt_order.end() - 1 - insert_distance)) break; + ++insert_distance; + } + rebuilt_order.insert(rebuilt_order.end() - insert_distance, idx); + s << VARINT(diff + insert_distance); + } + + // Output a final 0 to denote the end of the graph. + s << uint8_t{0}; + } + + template <typename Stream, typename SetType> + void Unser(Stream& s, DepGraph<SetType>& depgraph) + { + /** The dependency graph which we deserialize into first, with transactions in + * topological serialization order, not original cluster order. */ + DepGraph<SetType> topo_depgraph; + /** Mapping from cluster order to serialization order, used later to reconstruct the + * cluster order. */ + std::vector<ClusterIndex> reordering; + + // Read transactions in topological order. + try { + while (true) { + // Read size. Size 0 signifies the end of the DepGraph. + int32_t size; + s >> VARINT_MODE(size, VarIntMode::NONNEGATIVE_SIGNED); + size &= 0x3FFFFF; // Enough for size up to 4M. + static_assert(0x3FFFFF >= 4000000); + if (size == 0 || topo_depgraph.TxCount() == SetType::Size()) break; + // Read fee, encoded as an unsigned varint (odd=negative, even=non-negative). + uint64_t coded_fee; + s >> VARINT(coded_fee); + coded_fee &= 0xFFFFFFFFFFFFF; // Enough for fee between -21M...21M BTC. + static_assert(0xFFFFFFFFFFFFF > uint64_t{2} * 21000000 * 100000000); + auto fee = UnsignedToSigned(coded_fee); + // Extend topo_depgraph with the new transaction (at the end). + auto topo_idx = topo_depgraph.AddTransaction({fee, size}); + reordering.push_back(topo_idx); + // Read dependency information. + uint64_t diff = 0; //!< How many potential parents we have to skip. + s >> VARINT(diff); + for (ClusterIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { + /** Which topo_depgraph index we are currently considering as parent of topo_idx. */ + ClusterIndex dep_topo_idx = topo_idx - 1 - dep_dist; + // Ignore transactions which are already known ancestors of topo_idx. + if (topo_depgraph.Descendants(dep_topo_idx)[topo_idx]) continue; + if (diff == 0) { + // When the skip counter has reached 0, add an actual dependency. + topo_depgraph.AddDependency(dep_topo_idx, topo_idx); + // And read the number of skips after it. + s >> VARINT(diff); + } else { + // Otherwise, dep_topo_idx is not a parent. Decrement and continue. + --diff; + } + } + // If we reach this point, we can interpret the remaining skip value as how far from the + // end of reordering topo_idx should be placed (wrapping around), so move it to its + // correct location. The preliminary reordering.push_back(topo_idx) above was to make + // sure that if a deserialization exception occurs, topo_idx still appears somewhere. + reordering.pop_back(); + reordering.insert(reordering.end() - (diff % (reordering.size() + 1)), topo_idx); + } + } catch (const std::ios_base::failure&) {} + + // Construct the original cluster order depgraph. + depgraph = {}; + // Add transactions to depgraph in the original cluster order. + for (auto topo_idx : reordering) { + depgraph.AddTransaction(topo_depgraph.FeeRate(topo_idx)); + } + // Translate dependencies from topological to cluster order. + for (ClusterIndex idx = 0; idx < reordering.size(); ++idx) { + ClusterIndex topo_idx = reordering[idx]; + for (ClusterIndex dep_idx = 0; dep_idx < reordering.size(); ++dep_idx) { + ClusterIndex dep_topo_idx = reordering[dep_idx]; + if (topo_depgraph.Ancestors(topo_idx)[dep_topo_idx]) { + depgraph.AddDependency(dep_idx, idx); + } + } + } + } +}; + +/** Perform a sanity/consistency check on a DepGraph. */ +template<typename SetType> +void SanityCheck(const DepGraph<SetType>& depgraph) +{ + // Consistency check between ancestors internally. + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + // Transactions include themselves as ancestors. + assert(depgraph.Ancestors(i)[i]); + // If a is an ancestor of b, then b's ancestors must include all of a's ancestors. + for (auto a : depgraph.Ancestors(i)) { + assert(depgraph.Ancestors(i).IsSupersetOf(depgraph.Ancestors(a))); + } + } + // Consistency check between ancestors and descendants. + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + for (ClusterIndex j = 0; j < depgraph.TxCount(); ++j) { + assert(depgraph.Ancestors(i)[j] == depgraph.Descendants(j)[i]); + } + } + // If DepGraph is acyclic, serialize + deserialize must roundtrip. + if (IsAcyclic(depgraph)) { + std::vector<unsigned char> ser; + VectorWriter writer(ser, 0); + writer << Using<DepGraphFormatter>(depgraph); + SpanReader reader(ser); + DepGraph<TestBitSet> decoded_depgraph; + reader >> Using<DepGraphFormatter>(decoded_depgraph); + assert(depgraph == decoded_depgraph); + assert(reader.empty()); + // It must also deserialize correctly without the terminal 0 byte (as the deserializer + // will upon EOF still return what it read so far). + assert(ser.size() >= 1 && ser.back() == 0); + ser.pop_back(); + reader = SpanReader{ser}; + decoded_depgraph = {}; + reader >> Using<DepGraphFormatter>(decoded_depgraph); + assert(depgraph == decoded_depgraph); + assert(reader.empty()); + } +} + +/** Verify that a DepGraph corresponds to the information in a cluster. */ +template<typename SetType> +void VerifyDepGraphFromCluster(const Cluster<SetType>& cluster, const DepGraph<SetType>& depgraph) +{ + // Sanity check the depgraph, which includes a check for correspondence between ancestors and + // descendants, so it suffices to check just ancestors below. + SanityCheck(depgraph); + // Verify transaction count. + assert(cluster.size() == depgraph.TxCount()); + // Verify feerates. + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + assert(depgraph.FeeRate(i) == cluster[i].first); + } + // Verify ancestors. + for (ClusterIndex i = 0; i < depgraph.TxCount(); ++i) { + // Start with the transaction having itself as ancestor. + auto ancestors = SetType::Singleton(i); + // Add parents of ancestors to the set of ancestors until it stops changing. + while (true) { + const auto old_ancestors = ancestors; + for (auto ancestor : ancestors) { + ancestors |= cluster[ancestor].second; + } + if (old_ancestors == ancestors) break; + } + // Compare against depgraph. + assert(depgraph.Ancestors(i) == ancestors); + // Some additional sanity tests: + // - Every transaction has itself as ancestor. + assert(ancestors[i]); + // - Every transaction has its direct parents as ancestors. + for (auto parent : cluster[i].second) { + assert(ancestors[parent]); + } + } +} + +/** Perform a sanity check on a linearization. */ +template<typename SetType> +void SanityCheck(const DepGraph<SetType>& depgraph, Span<const ClusterIndex> linearization) +{ + // Check completeness. + assert(linearization.size() == depgraph.TxCount()); + TestBitSet done; + for (auto i : linearization) { + // Check transaction position is in range. + assert(i < depgraph.TxCount()); + // Check topology and lack of duplicates. + assert((depgraph.Ancestors(i) - done) == TestBitSet::Singleton(i)); + done.Set(i); + } +} + +} // namespace + +#endif // BITCOIN_TEST_UTIL_CLUSTER_LINEARIZE_H diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 9257a4964a..beefc32bee 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -28,7 +28,8 @@ void ConnmanTestMsg::Handshake(CNode& node, auto& connman{*this}; peerman.InitializeNode(node, local_services); - FlushSendBuffer(node); // Drop the version message added by InitializeNode. + peerman.SendMessages(&node); + FlushSendBuffer(node); // Drop the version message added by SendMessages. CSerializedNetMsg msg_version{ NetMsg::Make(NetMsgType::VERSION, @@ -118,20 +119,20 @@ std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candida candidates.reserve(n_candidates); for (int id = 0; id < n_candidates; ++id) { candidates.push_back({ - /*id=*/id, - /*m_connected=*/std::chrono::seconds{random_context.randrange(100)}, - /*m_min_ping_time=*/std::chrono::microseconds{random_context.randrange(100)}, - /*m_last_block_time=*/std::chrono::seconds{random_context.randrange(100)}, - /*m_last_tx_time=*/std::chrono::seconds{random_context.randrange(100)}, - /*fRelevantServices=*/random_context.randbool(), - /*m_relay_txs=*/random_context.randbool(), - /*fBloomFilter=*/random_context.randbool(), - /*nKeyedNetGroup=*/random_context.randrange(100), - /*prefer_evict=*/random_context.randbool(), - /*m_is_local=*/random_context.randbool(), - /*m_network=*/ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())], - /*m_noban=*/false, - /*m_conn_type=*/ConnectionType::INBOUND, + .id=id, + .m_connected=std::chrono::seconds{random_context.randrange(100)}, + .m_min_ping_time=std::chrono::microseconds{random_context.randrange(100)}, + .m_last_block_time=std::chrono::seconds{random_context.randrange(100)}, + .m_last_tx_time=std::chrono::seconds{random_context.randrange(100)}, + .fRelevantServices=random_context.randbool(), + .m_relay_txs=random_context.randbool(), + .fBloomFilter=random_context.randbool(), + .nKeyedNetGroup=random_context.randrange(100u), + .prefer_evict=random_context.randbool(), + .m_is_local=random_context.randbool(), + .m_network=ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())], + .m_noban=false, + .m_conn_type=ConnectionType::INBOUND, }); } return candidates; diff --git a/src/test/util/net.h b/src/test/util/net.h index d91d801132..043e317bf0 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -34,6 +34,11 @@ class Span; struct ConnmanTestMsg : public CConnman { using CConnman::CConnman; + void SetMsgProc(NetEventsInterface* msgproc) + { + m_msgproc = msgproc; + } + void SetPeerConnectTimeout(std::chrono::seconds timeout) { m_peer_connect_timeout = timeout; diff --git a/src/test/util/random.cpp b/src/test/util/random.cpp index 4c87ab8df8..47d03055e2 100644 --- a/src/test/util/random.cpp +++ b/src/test/util/random.cpp @@ -13,21 +13,26 @@ FastRandomContext g_insecure_rand_ctx; -/** Return the unsigned from the environment var if available, otherwise 0 */ -static uint256 GetUintFromEnv(const std::string& env_name) -{ - const char* num = std::getenv(env_name.c_str()); - if (!num) return {}; - return uint256S(num); -} +extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; -void Seed(FastRandomContext& ctx) +void SeedRandomForTest(SeedRand seedtype) { - // Should be enough to get the seed once for the process - static uint256 seed{}; static const std::string RANDOM_CTX_SEED{"RANDOM_CTX_SEED"}; - if (seed.IsNull()) seed = GetUintFromEnv(RANDOM_CTX_SEED); - if (seed.IsNull()) seed = GetRandHash(); + + // Do this once, on the first call, regardless of seedtype, because once + // MakeRandDeterministicDANGEROUS is called, the output of GetRandHash is + // no longer truly random. It should be enough to get the seed once for the + // process. + static const uint256 ctx_seed = []() { + // If RANDOM_CTX_SEED is set, use that as seed. + const char* num = std::getenv(RANDOM_CTX_SEED.c_str()); + if (num) return uint256S(num); + // Otherwise use a (truly) random value. + return GetRandHash(); + }(); + + const uint256& seed{seedtype == SeedRand::SEED ? ctx_seed : uint256::ZERO}; LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__, RANDOM_CTX_SEED, seed.GetHex()); - ctx = FastRandomContext(seed); + MakeRandDeterministicDANGEROUS(seed); + g_insecure_rand_ctx.Reseed(GetRandHash()); } diff --git a/src/test/util/random.h b/src/test/util/random.h index 18ab425e48..09a475f8b3 100644 --- a/src/test/util/random.h +++ b/src/test/util/random.h @@ -19,27 +19,13 @@ */ extern FastRandomContext g_insecure_rand_ctx; -/** - * Flag to make GetRand in random.h return the same number - */ -extern bool g_mock_deterministic_tests; - enum class SeedRand { ZEROS, //!< Seed with a compile time constant of zeros - SEED, //!< Call the Seed() helper + SEED, //!< Use (and report) random seed from environment, or a (truly) random one. }; -/** Seed the given random ctx or use the seed passed in via an environment var */ -void Seed(FastRandomContext& ctx); - -static inline void SeedInsecureRand(SeedRand seed = SeedRand::SEED) -{ - if (seed == SeedRand::ZEROS) { - g_insecure_rand_ctx = FastRandomContext(/*fDeterministic=*/true); - } else { - Seed(g_insecure_rand_ctx); - } -} +/** Seed the RNG for testing. This affects all randomness, except GetStrongRandBytes(). */ +void SeedRandomForTest(SeedRand seed = SeedRand::SEED); static inline uint32_t InsecureRand32() { diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index cc7b2d6546..3f48ea4375 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -6,8 +6,6 @@ #include <test/util/setup_common.h> -#include <kernel/validation_cache_sizes.h> - #include <addrman.h> #include <banman.h> #include <chainparams.h> @@ -30,7 +28,6 @@ #include <node/mempool_args.h> #include <node/miner.h> #include <node/peerman_args.h> -#include <node/validation_cache_args.h> #include <node/warnings.h> #include <noui.h> #include <policy/fees.h> @@ -68,7 +65,6 @@ #include <stdexcept> using kernel::BlockTreeDB; -using kernel::ValidationCacheSizes; using node::ApplyArgsManOptions; using node::BlockAssembler; using node::BlockManager; @@ -83,6 +79,18 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; /** Random context to get unique temp data dirs. Separate from g_insecure_rand_ctx, which can be seeded from a const env var */ static FastRandomContext g_insecure_rand_ctx_temp_path; +std::ostream& operator<<(std::ostream& os, const arith_uint256& num) +{ + os << num.ToString(); + return os; +} + +std::ostream& operator<<(std::ostream& os, const uint160& num) +{ + os << num.ToString(); + return os; +} + std::ostream& operator<<(std::ostream& os, const uint256& num) { os << num.ToString(); @@ -112,7 +120,7 @@ static void ExitFailure(std::string_view str_err) exit(EXIT_FAILURE); } -BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args) +BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts) : m_args{} { m_node.shutdown = &m_interrupt; @@ -129,7 +137,7 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto "-debugexclude=libevent", "-debugexclude=leveldb", }, - extra_args); + opts.extra_args); if (G_TEST_COMMAND_LINE_ARGUMENTS) { arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS()); } @@ -145,6 +153,10 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto } } + // Use randomly chosen seed for deterministic PRNG, so that (by default) test + // data directories use a random name that doesn't overlap with other tests. + SeedRandomForTest(SeedRand::SEED); + if (!m_node.args->IsArgSet("-testdatadir")) { // By default, the data directory has a random name const auto rand_str{g_insecure_rand_ctx_temp_path.rand256().ToString()}; @@ -178,7 +190,6 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root)); SelectParams(chainType); - SeedInsecureRand(); if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN); InitLogging(*m_node.args); AppInitParameterInteraction(*m_node.args); @@ -188,11 +199,6 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto m_node.ecc_context = std::make_unique<ECC_Context>(); SetupEnvironment(); - ValidationCacheSizes validation_cache_sizes{}; - ApplyArgsManOptions(*m_node.args, validation_cache_sizes); - Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes)); - Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes)); - m_node.chain = interfaces::MakeChain(m_node); static bool noui_connected = false; if (!noui_connected) { @@ -217,16 +223,18 @@ BasicTestingSetup::~BasicTestingSetup() gArgs.ClearArgs(); } -ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args) - : BasicTestingSetup(chainType, extra_args) +ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts) + : BasicTestingSetup(chainType, opts) { const CChainParams& chainparams = Params(); // We have to run a scheduler thread to prevent ActivateBestChain // from blocking due to queue overrun. - m_node.scheduler = std::make_unique<CScheduler>(); - m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); }); - m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(*m_node.scheduler)); + if (opts.setup_validation_interface) { + m_node.scheduler = std::make_unique<CScheduler>(); + m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); }); + m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(*m_node.scheduler)); + } m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES); bilingual_str error{}; @@ -261,7 +269,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto ChainTestingSetup::~ChainTestingSetup() { if (m_node.scheduler) m_node.scheduler->stop(); - m_node.validation_signals->FlushBackgroundCallbacks(); + if (m_node.validation_signals) m_node.validation_signals->FlushBackgroundCallbacks(); m_node.connman.reset(); m_node.banman.reset(); m_node.addrman.reset(); @@ -301,19 +309,19 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() TestingSetup::TestingSetup( const ChainType chainType, - const std::vector<const char*>& extra_args, - const bool coins_db_in_memory, - const bool block_tree_db_in_memory) - : ChainTestingSetup(chainType, extra_args) + TestOpts opts) + : ChainTestingSetup(chainType, opts) { - m_coins_db_in_memory = coins_db_in_memory; - m_block_tree_db_in_memory = block_tree_db_in_memory; + m_coins_db_in_memory = opts.coins_db_in_memory; + m_block_tree_db_in_memory = opts.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(); + if (!opts.setup_net) return; + m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>()); m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman, /*deterministic=*/false, @@ -336,11 +344,9 @@ TestingSetup::TestingSetup( } TestChain100Setup::TestChain100Setup( - const ChainType chain_type, - const std::vector<const char*>& extra_args, - const bool coins_db_in_memory, - const bool block_tree_db_in_memory) - : TestingSetup{ChainType::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory} + const ChainType chain_type, + TestOpts opts) + : TestingSetup{ChainType::REGTEST, opts} { SetMockTime(1598887952); constexpr std::array<unsigned char, 32> vchKey = { diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index dbd66e3585..9515f0255e 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -24,6 +24,7 @@ #include <type_traits> #include <vector> +class arith_uint256; class CFeeRate; class Chainstate; class FastRandomContext; @@ -48,6 +49,14 @@ std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::os static constexpr CAmount CENT{1000000}; +struct TestOpts { + std::vector<const char*> extra_args{}; + bool coins_db_in_memory{true}; + bool block_tree_db_in_memory{true}; + bool setup_net{true}; + bool setup_validation_interface{true}; +}; + /** Basic testing setup. * This just configures logging, data dir and chain parameters. */ @@ -55,7 +64,7 @@ struct BasicTestingSetup { util::SignalInterrupt m_interrupt; node::NodeContext m_node; // keep as first member to be destructed last - explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, const std::vector<const char*>& extra_args = {}); + explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {}); ~BasicTestingSetup(); fs::path m_path_root; @@ -73,7 +82,7 @@ struct ChainTestingSetup : public BasicTestingSetup { bool m_coins_db_in_memory{true}; bool m_block_tree_db_in_memory{true}; - explicit ChainTestingSetup(const ChainType chainType = ChainType::MAIN, const std::vector<const char*>& extra_args = {}); + explicit ChainTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {}); ~ChainTestingSetup(); // Supplies a chainstate, if one is needed @@ -85,9 +94,7 @@ struct ChainTestingSetup : public BasicTestingSetup { struct TestingSetup : public ChainTestingSetup { explicit TestingSetup( const ChainType chainType = ChainType::MAIN, - const std::vector<const char*>& extra_args = {}, - const bool coins_db_in_memory = true, - const bool block_tree_db_in_memory = true); + TestOpts = {}); }; /** Identical to TestingSetup, but chain set to regtest */ @@ -106,9 +113,7 @@ class CScript; struct TestChain100Setup : public TestingSetup { TestChain100Setup( const ChainType chain_type = ChainType::REGTEST, - const std::vector<const char*>& extra_args = {}, - const bool coins_db_in_memory = true, - const bool block_tree_db_in_memory = true); + TestOpts = {}); /** * Create a new block with just given transactions, coinbase paying to @@ -220,21 +225,23 @@ struct TestChain100Setup : public TestingSetup { * be used in "hot loops", for example fuzzing or benchmarking. */ template <class T = const BasicTestingSetup> -std::unique_ptr<T> MakeNoLogFileContext(const ChainType chain_type = ChainType::REGTEST, const std::vector<const char*>& extra_args = {}) +std::unique_ptr<T> MakeNoLogFileContext(const ChainType chain_type = ChainType::REGTEST, TestOpts opts = {}) { - const std::vector<const char*> arguments = Cat( + opts.extra_args = Cat( { "-nodebuglogfile", "-nodebug", }, - extra_args); + opts.extra_args); - return std::make_unique<T>(chain_type, arguments); + return std::make_unique<T>(chain_type, opts); } CBlock getBlock13b8a(); -// define an implicit conversion here so that uint256 may be used directly in BOOST_CHECK_* +// Make types usable in BOOST_CHECK_* +std::ostream& operator<<(std::ostream& os, const arith_uint256& num); +std::ostream& operator<<(std::ostream& os, const uint160& num); std::ostream& operator<<(std::ostream& os, const uint256& num); /** diff --git a/src/test/util/xoroshiro128plusplus.h b/src/test/util/xoroshiro128plusplus.h deleted file mode 100644 index ac9f59b3f5..0000000000 --- a/src/test/util/xoroshiro128plusplus.h +++ /dev/null @@ -1,71 +0,0 @@ -// 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 a371753adf..bf1fc1ea0a 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -58,7 +58,7 @@ static const std::string STRING_WITH_EMBEDDED_NULL_CHAR{"1"s "\0" "1"s}; /* defined in logging.cpp */ namespace BCLog { - std::string LogEscapeMessage(const std::string& str); + std::string LogEscapeMessage(std::string_view str); } BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) @@ -459,7 +459,7 @@ BOOST_AUTO_TEST_CASE(util_IsHexNumber) BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - SeedInsecureRand(SeedRand::ZEROS); + SeedRandomForTest(SeedRand::ZEROS); for (int mod=2;mod<11;mod++) { int mask = 1; @@ -1508,8 +1508,10 @@ struct Tracker Tracker(Tracker&& t) noexcept : origin(t.origin), copies(t.copies) {} Tracker& operator=(const Tracker& t) noexcept { - origin = t.origin; - copies = t.copies + 1; + if (this != &t) { + origin = t.origin; + copies = t.copies + 1; + } return *this; } }; diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 1641c4cd22..cf819f8751 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -167,9 +167,10 @@ struct SnapshotTestSetup : TestChain100Setup { // destructive filesystem operations. SnapshotTestSetup() : TestChain100Setup{ {}, - {}, - /*coins_db_in_memory=*/false, - /*block_tree_db_in_memory=*/false, + { + .coins_db_in_memory = false, + .block_tree_db_in_memory = false, + }, } { } @@ -284,7 +285,7 @@ struct SnapshotTestSetup : TestChain100Setup { const auto& au_data = ::Params().AssumeutxoForHeight(snapshot_height); const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()); - BOOST_CHECK_EQUAL(tip->nChainTx, au_data->nChainTx); + BOOST_CHECK_EQUAL(tip->m_chain_tx_count, au_data->m_chain_tx_count); // To be checked against later when we try loading a subsequent snapshot. uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()}; @@ -464,7 +465,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) { index->nStatus = BlockStatus::BLOCK_VALID_TREE; index->nTx = 0; - index->nChainTx = 0; + index->m_chain_tx_count = 0; } ++num_indexes; diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp index 93a884be6d..2e378ed30b 100644 --- a/src/test/validation_tests.cpp +++ b/src/test/validation_tests.cpp @@ -143,11 +143,11 @@ BOOST_AUTO_TEST_CASE(test_assumeutxo) const auto out110 = *params->AssumeutxoForHeight(110); BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1"); - BOOST_CHECK_EQUAL(out110.nChainTx, 111U); + BOOST_CHECK_EQUAL(out110.m_chain_tx_count, 111U); - const auto out110_2 = *params->AssumeutxoForBlockhash(uint256S("0x696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c")); + const auto out110_2 = *params->AssumeutxoForBlockhash(uint256{"696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c"}); BOOST_CHECK_EQUAL(out110_2.hash_serialized.ToString(), "6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1"); - BOOST_CHECK_EQUAL(out110_2.nChainTx, 111U); + BOOST_CHECK_EQUAL(out110_2.m_chain_tx_count, 111U); } BOOST_AUTO_TEST_CASE(block_malleation) diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index f462895edb..896840b0f3 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -419,7 +419,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) // check that any deployment on any chain can conceivably reach both // ACTIVE and FAILED states in roughly the way we expect - for (const auto& chain_type: {ChainType::MAIN, ChainType::TESTNET, ChainType::SIGNET, ChainType::REGTEST}) { + for (const auto& chain_type: {ChainType::MAIN, ChainType::TESTNET, ChainType::TESTNET4, ChainType::SIGNET, ChainType::REGTEST}) { const auto chainParams = CreateChainParams(*m_node.args, chain_type); uint32_t chain_all_vbits{0}; for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) { diff --git a/src/test/xoroshiro128plusplus_tests.cpp b/src/test/xoroshiro128plusplus_tests.cpp deleted file mode 100644 index ea1b3e355f..0000000000 --- a/src/test/xoroshiro128plusplus_tests.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// 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/threadsafety.h b/src/threadsafety.h index 28b6177927..2e9a39bfc9 100644 --- a/src/threadsafety.h +++ b/src/threadsafety.h @@ -71,7 +71,7 @@ class SCOPED_LOCKABLE StdLockGuard : public std::lock_guard<StdMutex> { public: explicit StdLockGuard(StdMutex& cs) EXCLUSIVE_LOCK_FUNCTION(cs) : std::lock_guard<StdMutex>(cs) {} - ~StdLockGuard() UNLOCK_FUNCTION() {} + ~StdLockGuard() UNLOCK_FUNCTION() = default; }; #endif // BITCOIN_THREADSAFETY_H diff --git a/src/tinyformat.h b/src/tinyformat.h index 3ec385bc95..f536306375 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -507,8 +507,7 @@ namespace detail { class FormatArg { public: - FormatArg() - { } + FormatArg() = default; template<typename T> explicit FormatArg(const T& value) diff --git a/src/txdb.cpp b/src/txdb.cpp index e4a4b3bf72..3865692b6a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -88,7 +88,7 @@ std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const { return vhashHeadBlocks; } -bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) { +bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { CDBBatch batch(*m_db); size_t count = 0; size_t changed = 0; @@ -114,8 +114,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo batch.Erase(DB_BEST_BLOCK); batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip)); - for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { - if (it->second.flags & CCoinsCacheEntry::DIRTY) { + for (auto it{cursor.Begin()}; it != cursor.End();) { + if (it->second.IsDirty()) { CoinEntry entry(&it->first); if (it->second.coin.IsSpent()) batch.Erase(entry); @@ -124,7 +124,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo changed++; } count++; - it = erase ? mapCoins.erase(it) : std::next(it); + it = cursor.NextAndMaybeErase(*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); diff --git a/src/txdb.h b/src/txdb.h index c9af0a091e..e0acb09e98 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -63,7 +63,7 @@ public: bool HaveCoin(const COutPoint &outpoint) const override; uint256 GetBestBlock() const override; std::vector<uint256> GetHeadBlocks() const override; - bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase = true) override; + bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override; std::unique_ptr<CCoinsViewCursor> Cursor() const override; //! Whether an unsupported database format is used. diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 10674c07ac..b523c5fe09 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -15,7 +15,6 @@ #include <policy/policy.h> #include <policy/settings.h> #include <random.h> -#include <reverse_iterator.h> #include <tinyformat.h> #include <util/check.h> #include <util/feefrac.h> @@ -31,6 +30,7 @@ #include <cmath> #include <numeric> #include <optional> +#include <ranges> #include <string_view> #include <utility> @@ -121,7 +121,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes // This maximizes the benefit of the descendant cache and guarantees that // CTxMemPoolEntry::m_children will be updated, an assumption made in // UpdateForDescendants. - for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) { + for (const uint256& hash : vHashesToUpdate | std::views::reverse) { // calculate children from mapNextTx txiter it = mapTx.find(hash); if (it == mapTx.end()) { @@ -657,7 +657,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei { if (m_opts.check_ratio == 0) return; - if (GetRand(m_opts.check_ratio) >= 1) return; + if (FastRandomContext().randrange(m_opts.check_ratio) >= 1) return; AssertLockHeld(::cs_main); LOCK(cs); diff --git a/src/txmempool.h b/src/txmempool.h index 52f186f0ff..d0cb41a078 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -329,9 +329,7 @@ public: static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing - typedef boost::multi_index_container< - CTxMemPoolEntry, - boost::multi_index::indexed_by< + struct CTxMemPoolEntry_Indices final : boost::multi_index::indexed_by< // sorted by txid boost::multi_index::hashed_unique<mempoolentry_txid, SaltedTxidHasher>, // sorted by wtxid @@ -359,6 +357,10 @@ public: CompareTxMemPoolEntryByAncestorFee > > + {}; + typedef boost::multi_index_container< + CTxMemPoolEntry, + CTxMemPoolEntry_Indices > indexed_transaction_set; /** @@ -366,9 +368,7 @@ public: * that are guarded by it. * * @par Consistency guarantees - * * By design, it is guaranteed that: - * * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool * that is consistent with current chain tip (`ActiveChain()` and * `CoinsTip()`) and is fully populated. Fully populated means that if the @@ -376,7 +376,6 @@ public: * previously active chain, all the missing transactions will have been * re-added to the mempool and should be present if they meet size and * consistency constraints. - * * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool * consistent with some chain that was active since `cs_main` was last * locked, and that is fully populated as described above. It is ok for diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp index 3eaf53939d..faab208333 100644 --- a/src/txorphanage.cpp +++ b/src/txorphanage.cpp @@ -12,16 +12,8 @@ #include <cassert> -/** Expiration time for orphan transactions */ -static constexpr auto ORPHAN_TX_EXPIRE_TIME{20min}; -/** Minimum time between orphan transactions expire time checks */ -static constexpr auto ORPHAN_TX_EXPIRE_INTERVAL{5min}; - - bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) { - LOCK(m_mutex); - const Txid& hash = tx->GetHash(); const Wtxid& wtxid = tx->GetWitnessHash(); if (m_orphans.count(wtxid)) @@ -55,13 +47,6 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer) int TxOrphanage::EraseTx(const Wtxid& wtxid) { - LOCK(m_mutex); - return EraseTxNoLock(wtxid); -} - -int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) -{ - AssertLockHeld(m_mutex); std::map<Wtxid, OrphanTx>::iterator it = m_orphans.find(wtxid); if (it == m_orphans.end()) return 0; @@ -97,8 +82,6 @@ int TxOrphanage::EraseTxNoLock(const Wtxid& wtxid) void TxOrphanage::EraseForPeer(NodeId peer) { - LOCK(m_mutex); - m_peer_work_set.erase(peer); int nErased = 0; @@ -108,7 +91,7 @@ void TxOrphanage::EraseForPeer(NodeId peer) // increment to avoid iterator becoming invalid after erasure const auto& [wtxid, orphan] = *iter++; if (orphan.fromPeer == peer) { - nErased += EraseTxNoLock(wtxid); + nErased += EraseTx(wtxid); } } if (nErased > 0) LogPrint(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) from peer=%d\n", nErased, peer); @@ -116,8 +99,6 @@ void TxOrphanage::EraseForPeer(NodeId peer) void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { - LOCK(m_mutex); - unsigned int nEvicted = 0; auto nNow{Now<NodeSeconds>()}; if (m_next_sweep <= nNow) { @@ -129,7 +110,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { std::map<Wtxid, OrphanTx>::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseTxNoLock(maybeErase->second.tx->GetWitnessHash()); + nErased += EraseTx(maybeErase->second.tx->GetWitnessHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); } @@ -142,7 +123,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) { // Evict a random orphan: size_t randompos = rng.randrange(m_orphan_list.size()); - EraseTxNoLock(m_orphan_list[randompos]->second.tx->GetWitnessHash()); + EraseTx(m_orphan_list[randompos]->second.tx->GetWitnessHash()); ++nEvicted; } if (nEvicted > 0) LogPrint(BCLog::TXPACKAGES, "orphanage overflow, removed %u tx\n", nEvicted); @@ -150,9 +131,6 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx) { - 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()) { @@ -171,14 +149,11 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx) bool TxOrphanage::HaveTx(const Wtxid& wtxid) const { - LOCK(m_mutex); return m_orphans.count(wtxid); } CTransactionRef TxOrphanage::GetTxToReconsider(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; @@ -197,8 +172,6 @@ CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer) 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; @@ -209,8 +182,6 @@ bool TxOrphanage::HaveTxToReconsider(NodeId peer) void TxOrphanage::EraseForBlock(const CBlock& block) { - LOCK(m_mutex); - std::vector<Wtxid> vOrphanErase; for (const CTransactionRef& ptx : block.vtx) { @@ -231,7 +202,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block) if (vOrphanErase.size()) { int nErased = 0; for (const auto& orphanHash : vOrphanErase) { - nErased += EraseTxNoLock(orphanHash); + nErased += EraseTx(orphanHash); } LogPrint(BCLog::TXPACKAGES, "Erased %d orphan transaction(s) included or conflicted by block\n", nErased); } @@ -239,8 +210,6 @@ void TxOrphanage::EraseForBlock(const CBlock& block) std::vector<CTransactionRef> TxOrphanage::GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const { - LOCK(m_mutex); - // First construct a vector of iterators to ensure we do not return duplicates of the same tx // and so we can sort by nTimeExpire. std::vector<OrphanMap::iterator> iters; @@ -281,8 +250,6 @@ std::vector<CTransactionRef> TxOrphanage::GetChildrenFromSamePeer(const CTransac std::vector<std::pair<CTransactionRef, NodeId>> TxOrphanage::GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const { - LOCK(m_mutex); - // First construct vector of iterators to ensure we do not return duplicates of the same tx. std::vector<OrphanMap::iterator> iters; diff --git a/src/txorphanage.h b/src/txorphanage.h index 3083c8467f..2c53d1d40f 100644 --- a/src/txorphanage.h +++ b/src/txorphanage.h @@ -14,63 +14,65 @@ #include <map> #include <set> +/** Expiration time for orphan transactions */ +static constexpr auto ORPHAN_TX_EXPIRE_TIME{20min}; +/** Minimum time between orphan transactions expire time checks */ +static constexpr auto ORPHAN_TX_EXPIRE_INTERVAL{5min}; + /** A class to track orphan transactions (failed on TX_MISSING_INPUTS) * Since we cannot distinguish orphans from bad transactions with * non-existent inputs, we heavily limit the number of orphans * we keep and the duration we keep them for. + * Not thread-safe. Requires external synchronization. */ class TxOrphanage { public: /** Add a new orphan transaction */ - bool AddTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + bool AddTx(const CTransactionRef& tx, NodeId peer); /** Check if we already have an orphan transaction (by wtxid only) */ - bool HaveTx(const Wtxid& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + bool HaveTx(const Wtxid& wtxid) const; /** 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. */ - CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + CTransactionRef GetTxToReconsider(NodeId peer); /** Erase an orphan by wtxid */ - int EraseTx(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + int EraseTx(const Wtxid& wtxid); /** Erase all orphans announced by a peer (eg, after that peer disconnects) */ - void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void EraseForPeer(NodeId peer); /** Erase all orphans included in or invalidated by a new block */ - void EraseForBlock(const CBlock& block) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void EraseForBlock(const CBlock& block); /** Limit the orphanage to the given maximum */ - void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng); /** 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);; + void AddChildrenToWorkSet(const CTransaction& tx); /** Does this peer have any work to do? */ - bool HaveTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);; + bool HaveTxToReconsider(NodeId peer); /** Get all children that spend from this tx and were received from nodeid. Sorted from most * recent to least recent. */ - std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const; /** Get all children that spend from this tx but were not received from nodeid. Also return * which peer provided each tx. */ - std::vector<std::pair<CTransactionRef, NodeId>> GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + std::vector<std::pair<CTransactionRef, NodeId>> GetChildrenFromDifferentPeer(const CTransactionRef& parent, NodeId nodeid) const; /** Return how many entries exist in the orphange */ - size_t Size() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + size_t Size() { - LOCK(m_mutex); return m_orphans.size(); } protected: - /** Guards orphan transactions */ - mutable Mutex m_mutex; - struct OrphanTx { CTransactionRef tx; NodeId fromPeer; @@ -80,10 +82,10 @@ protected: /** Map from wtxid to orphan transaction record. Limited by * -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */ - std::map<Wtxid, OrphanTx> m_orphans GUARDED_BY(m_mutex); + std::map<Wtxid, OrphanTx> m_orphans; /** Which peer provided the orphans that need to be reconsidered */ - std::map<NodeId, std::set<Wtxid>> m_peer_work_set GUARDED_BY(m_mutex); + std::map<NodeId, std::set<Wtxid>> m_peer_work_set; using OrphanMap = decltype(m_orphans); @@ -98,16 +100,13 @@ 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(m_mutex); + std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it; /** Orphan transactions in vector for quick random eviction */ - std::vector<OrphanMap::iterator> m_orphan_list GUARDED_BY(m_mutex); - - /** Erase an orphan by wtxid */ - int EraseTxNoLock(const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex); + std::vector<OrphanMap::iterator> m_orphan_list; /** Timestamp for the next scheduled sweep of expired orphans */ - NodeSeconds m_next_sweep GUARDED_BY(m_mutex){0s}; + NodeSeconds m_next_sweep{0s}; }; #endif // BITCOIN_TXORPHANAGE_H diff --git a/src/txrequest.cpp b/src/txrequest.cpp index ce5fbd9a7f..96ea716481 100644 --- a/src/txrequest.cpp +++ b/src/txrequest.cpp @@ -113,8 +113,8 @@ class PriorityComputer { const uint64_t m_k0, m_k1; public: explicit PriorityComputer(bool deterministic) : - m_k0{deterministic ? 0 : GetRand(0xFFFFFFFFFFFFFFFF)}, - m_k1{deterministic ? 0 : GetRand(0xFFFFFFFFFFFFFFFF)} {} + m_k0{deterministic ? 0 : FastRandomContext().rand64()}, + m_k1{deterministic ? 0 : FastRandomContext().rand64()} {} Priority operator()(const uint256& txhash, NodeId peer, bool preferred) const { @@ -212,14 +212,17 @@ struct ByTimeViewExtractor } }; +struct Announcement_Indices final : boost::multi_index::indexed_by< + boost::multi_index::ordered_unique<boost::multi_index::tag<ByPeer>, ByPeerViewExtractor>, + boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTxHash>, ByTxHashViewExtractor>, + boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTime>, ByTimeViewExtractor> +> +{}; + /** Data type for the main data structure (Announcement objects with ByPeer/ByTxHash/ByTime indexes). */ using Index = boost::multi_index_container< Announcement, - boost::multi_index::indexed_by< - boost::multi_index::ordered_unique<boost::multi_index::tag<ByPeer>, ByPeerViewExtractor>, - boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTxHash>, ByTxHashViewExtractor>, - boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTime>, ByTimeViewExtractor> - > + Announcement_Indices >; /** Helper type to simplify syntax of iterator types. */ diff --git a/src/uint256.cpp b/src/uint256.cpp index 7f81c3c448..2756a7f5cd 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -18,40 +18,32 @@ std::string base_blob<BITS>::GetHex() const } template <unsigned int BITS> -void base_blob<BITS>::SetHex(const char* psz) +void base_blob<BITS>::SetHexDeprecated(const std::string_view str) { std::fill(m_data.begin(), m_data.end(), 0); - // skip leading spaces - while (IsSpace(*psz)) - psz++; + const auto trimmed = util::RemovePrefixView(util::TrimStringView(str), "0x"); - // skip 0x - if (psz[0] == '0' && ToLower(psz[1]) == 'x') - psz += 2; - - // hex string to uint + // Note: if we are passed a greater number of digits than would fit as bytes + // in m_data, we will be discarding the leftmost ones. + // str="12bc" in a WIDTH=1 m_data => m_data[] == "\0xbc", not "0x12". size_t digits = 0; - while (::HexDigit(psz[digits]) != -1) - digits++; + for (const char c : trimmed) { + if (::HexDigit(c) == -1) break; + ++digits; + } unsigned char* p1 = m_data.data(); unsigned char* pend = p1 + WIDTH; while (digits > 0 && p1 < pend) { - *p1 = ::HexDigit(psz[--digits]); + *p1 = ::HexDigit(trimmed[--digits]); if (digits > 0) { - *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4); + *p1 |= ((unsigned char)::HexDigit(trimmed[--digits]) << 4); p1++; } } } template <unsigned int BITS> -void base_blob<BITS>::SetHex(const std::string& str) -{ - SetHex(str.c_str()); -} - -template <unsigned int BITS> std::string base_blob<BITS>::ToString() const { return (GetHex()); @@ -60,14 +52,12 @@ std::string base_blob<BITS>::ToString() const // Explicit instantiations for base_blob<160> 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&); +template void base_blob<160>::SetHexDeprecated(std::string_view); // Explicit instantiations for base_blob<256> template std::string base_blob<256>::GetHex() const; template std::string base_blob<256>::ToString() const; -template void base_blob<256>::SetHex(const char*); -template void base_blob<256>::SetHex(const std::string&); +template void base_blob<256>::SetHexDeprecated(std::string_view); const uint256 uint256::ZERO(0); const uint256 uint256::ONE(1); diff --git a/src/uint256.h b/src/uint256.h index d35b3a66fa..cf008765bd 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2022 The Bitcoin Core developers +// Copyright (c) 2009-present 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,12 +8,14 @@ #include <crypto/common.h> #include <span.h> +#include <util/strencodings.h> #include <algorithm> #include <array> #include <cassert> +#include <cstdint> #include <cstring> -#include <stdint.h> +#include <optional> #include <string> /** Template base class for fixed-sized opaque blobs. */ @@ -39,6 +41,8 @@ public: std::copy(vch.begin(), vch.end(), m_data.begin()); } + consteval explicit base_blob(std::string_view hex_str); + constexpr bool IsNull() const { return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) { @@ -51,16 +55,46 @@ public: std::fill(m_data.begin(), m_data.end(), 0); } + /** Lexicographic ordering + * @note Does NOT match the ordering on the corresponding \ref + * base_uint::CompareTo, which starts comparing from the end. + */ constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); } 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; } + /** @name Hex representation + * + * The reverse-byte hex representation is a convenient way to view the blob + * as a number, because it is consistent with the way the base_uint class + * converts blobs to numbers. + * + * @note base_uint treats the blob as an array of bytes with the numerically + * least significant byte first and the most significant byte last. Because + * numbers are typically written with the most significant digit first and + * the least significant digit last, the reverse hex display of the blob + * corresponds to the same numeric value that base_uint interprets from the + * blob. + * @{*/ std::string GetHex() const; - void SetHex(const char* psz); - void SetHex(const std::string& str); + /** Unlike FromHex this accepts any invalid input, thus it is fragile and deprecated! + * + * - Hex numbers that don't specify enough bytes to fill the internal array + * will be treated as setting the beginning of it, which corresponds to + * the least significant bytes when converted to base_uint. + * + * - Hex numbers specifying too many bytes will have the numerically most + * significant bytes (the beginning of the string) narrowed away. + * + * - An odd count of hex digits will result in the high bits of the leftmost + * byte being zero. + * "0x123" => {0x23, 0x1, 0x0, ..., 0x0} + */ + void SetHexDeprecated(std::string_view str); std::string ToString() const; + /**@}*/ constexpr const unsigned char* data() const { return m_data.data(); } constexpr unsigned char* data() { return m_data.data(); } @@ -88,12 +122,50 @@ public: } }; +template <unsigned int BITS> +consteval base_blob<BITS>::base_blob(std::string_view hex_str) +{ + // Non-lookup table version of HexDigit(). + auto from_hex = [](const char c) -> int8_t { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + + assert(false); // Reached if ctor is called with an invalid hex digit. + }; + + assert(hex_str.length() == m_data.size() * 2); // 2 hex digits per byte. + auto str_it = hex_str.rbegin(); + for (auto& elem : m_data) { + auto lo = from_hex(*(str_it++)); + elem = (from_hex(*(str_it++)) << 4) | lo; + } +} + +namespace detail { +/** + * Writes the hex string (in reverse byte order) into a new uintN_t object + * and only returns a value iff all of the checks pass: + * - Input length is uintN_t::size()*2 + * - All characters are hex + */ +template <class uintN_t> +std::optional<uintN_t> FromHex(std::string_view str) +{ + if (uintN_t::size() * 2 != str.size() || !IsHex(str)) return std::nullopt; + uintN_t rv; + rv.SetHexDeprecated(str); + return rv; +} +} // namespace detail + /** 160-bit opaque blob. * @note This type is called uint160 for historical reasons only. It is an opaque * blob of 160 bits and has no integer operations. */ class uint160 : public base_blob<160> { public: + static std::optional<uint160> FromHex(std::string_view str) { return detail::FromHex<uint160>(str); } constexpr uint160() = default; constexpr explicit uint160(Span<const unsigned char> vch) : base_blob<160>(vch) {} }; @@ -105,31 +177,22 @@ public: */ class uint256 : public base_blob<256> { public: + static std::optional<uint256> FromHex(std::string_view str) { return detail::FromHex<uint256>(str); } constexpr uint256() = default; + consteval explicit uint256(std::string_view hex_str) : base_blob<256>(hex_str) {} constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {} constexpr explicit uint256(Span<const unsigned char> vch) : base_blob<256>(vch) {} static const uint256 ZERO; static const uint256 ONE; }; -/* uint256 from const char *. - * This is a separate function because the constructor uint256(const char*) can result - * in dangerously catching uint256(0). - */ -inline uint256 uint256S(const char *str) -{ - uint256 rv; - rv.SetHex(str); - return rv; -} -/* uint256 from std::string. - * This is a separate function because the constructor uint256(const std::string &str) can result - * in dangerously catching uint256(0) via std::string(const char*). +/* uint256 from std::string_view, containing byte-reversed hex encoding. + * DEPRECATED. Unlike FromHex this accepts any invalid input, thus it is fragile and deprecated! */ -inline uint256 uint256S(const std::string& str) +inline uint256 uint256S(std::string_view str) { uint256 rv; - rv.SetHex(str); + rv.SetHexDeprecated(str); return rv; } diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 1c724555f3..2577c682d7 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -20,17 +20,17 @@ try { \ (stmt); \ assert(0 && "No exception caught"); \ - } catch (excMatch & e) { \ - } catch (...) { \ - assert(0 && "Wrong exception caught"); \ - } \ + } catch (excMatch&) { \ + } catch (...) { \ + assert(0 && "Wrong exception caught"); \ + } \ } #define BOOST_CHECK_NO_THROW(stmt) { \ try { \ (stmt); \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } void univalue_constructor() diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp index 92f1dbd5d8..79e4a21fe9 100644 --- a/src/util/bytevectorhash.cpp +++ b/src/util/bytevectorhash.cpp @@ -9,8 +9,8 @@ #include <vector> ByteVectorHash::ByteVectorHash() : - m_k0(GetRand<uint64_t>()), - m_k1(GetRand<uint64_t>()) + m_k0(FastRandomContext().rand64()), + m_k1(FastRandomContext().rand64()) { } diff --git a/src/util/chaintype.cpp b/src/util/chaintype.cpp index 8a199e352a..272466e7af 100644 --- a/src/util/chaintype.cpp +++ b/src/util/chaintype.cpp @@ -15,6 +15,8 @@ std::string ChainTypeToString(ChainType chain) return "main"; case ChainType::TESTNET: return "test"; + case ChainType::TESTNET4: + return "testnet4"; case ChainType::SIGNET: return "signet"; case ChainType::REGTEST: @@ -29,6 +31,8 @@ std::optional<ChainType> ChainTypeFromString(std::string_view chain) return ChainType::MAIN; } else if (chain == "test") { return ChainType::TESTNET; + } else if (chain == "testnet4") { + return ChainType::TESTNET4; } else if (chain == "signet") { return ChainType::SIGNET; } else if (chain == "regtest") { diff --git a/src/util/chaintype.h b/src/util/chaintype.h index c73985df57..2fe734b64a 100644 --- a/src/util/chaintype.h +++ b/src/util/chaintype.h @@ -13,6 +13,7 @@ enum class ChainType { TESTNET, SIGNET, REGTEST, + TESTNET4, }; std::string ChainTypeToString(ChainType chain); diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp index f571725786..3109ba02a8 100644 --- a/src/util/hasher.cpp +++ b/src/util/hasher.cpp @@ -7,14 +7,18 @@ #include <span.h> #include <util/hasher.h> -SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand<uint64_t>()), k1(GetRand<uint64_t>()) {} +SaltedTxidHasher::SaltedTxidHasher() : + k0{FastRandomContext().rand64()}, + k1{FastRandomContext().rand64()} {} SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : - k0(deterministic ? 0x8e819f2607a18de6 : GetRand<uint64_t>()), - k1(deterministic ? 0xf4020d2e3983b0eb : GetRand<uint64_t>()) + k0{deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64()}, + k1{deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()} {} -SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand<uint64_t>()), m_k1(GetRand<uint64_t>()) {} +SaltedSipHasher::SaltedSipHasher() : + m_k0{FastRandomContext().rand64()}, + m_k1{FastRandomContext().rand64()} {} size_t SaltedSipHasher::operator()(const Span<const unsigned char>& script) const { diff --git a/src/util/string.h b/src/util/string.h index e2e470f4ab..30c0a0d6c1 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -81,6 +81,14 @@ std::vector<T> Split(const Span<const char>& sp, char sep) return std::string(TrimStringView(str, pattern)); } +[[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix) +{ + if (str.ends_with(suffix)) { + return str.substr(0, str.size() - suffix.size()); + } + return str; +} + [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix) { if (str.substr(0, prefix.size()) == prefix) { diff --git a/src/util/subprocess.h b/src/util/subprocess.h index e76ced687c..3449fa3b1b 100644 --- a/src/util/subprocess.h +++ b/src/util/subprocess.h @@ -678,7 +678,7 @@ struct error class Buffer { public: - Buffer() {} + Buffer() = default; explicit Buffer(size_t cap) { buf.resize(cap); } void add_cap(size_t cap) { buf.resize(cap); } diff --git a/src/util/task_runner.h b/src/util/task_runner.h index d3cd8007de..951381823b 100644 --- a/src/util/task_runner.h +++ b/src/util/task_runner.h @@ -19,7 +19,7 @@ namespace util { class TaskRunnerInterface { public: - virtual ~TaskRunnerInterface() {} + virtual ~TaskRunnerInterface() = default; /** * The callback can either be queued for later/asynchronous/threaded diff --git a/src/util/transaction_identifier.h b/src/util/transaction_identifier.h index d4a0ede25a..81b053843d 100644 --- a/src/util/transaction_identifier.h +++ b/src/util/transaction_identifier.h @@ -42,6 +42,12 @@ public: /** Wrapped `uint256` methods. */ constexpr bool IsNull() const { return m_wrapped.IsNull(); } constexpr void SetNull() { m_wrapped.SetNull(); } + static std::optional<transaction_identifier> FromHex(std::string_view hex) + { + auto u{uint256::FromHex(hex)}; + if (!u) return std::nullopt; + return FromUint256(*u); + } std::string GetHex() const { return m_wrapped.GetHex(); } std::string ToString() const { return m_wrapped.ToString(); } static constexpr auto size() { return decltype(m_wrapped)::size(); } @@ -66,9 +72,4 @@ using Txid = transaction_identifier<false>; /** Wtxid commits to all transaction fields including the witness. */ using Wtxid = transaction_identifier<true>; -inline Txid TxidFromString(std::string_view str) -{ - return Txid::FromUint256(uint256S(str.data())); -} - #endif // BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H diff --git a/src/util/translation.h b/src/util/translation.h index d33fd2d0a0..6effe102f9 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2022 The Bitcoin Core developers +// Copyright (c) 2019-present 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,13 +67,19 @@ bilingual_str format(const bilingual_str& fmt, const Args&... args) /** Translate a message to the native language of the user. */ const extern std::function<std::string(const char*)> G_TRANSLATION_FUN; +struct ConstevalStringLiteral { + const char* const lit; + consteval ConstevalStringLiteral(const char* str) : lit{str} {} + consteval ConstevalStringLiteral(std::nullptr_t) = delete; +}; + /** * Translation function. * If no translation function is set, simply return the input. */ -inline bilingual_str _(const char* psz) +inline bilingual_str _(ConstevalStringLiteral str) { - return bilingual_str{psz, G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz}; + return bilingual_str{str.lit, G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(str.lit) : str.lit}; } #endif // BITCOIN_UTIL_TRANSLATION_H diff --git a/src/validation.cpp b/src/validation.cpp index 7b586c45b8..bf2b4b315e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2022 The Bitcoin Core developers +// Copyright (c) 2009-present 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,6 @@ #include <primitives/block.h> #include <primitives/transaction.h> #include <random.h> -#include <reverse_iterator.h> #include <script/script.h> #include <script/sigcache.h> #include <signet.h> @@ -70,6 +69,7 @@ #include <deque> #include <numeric> #include <optional> +#include <ranges> #include <string> #include <tuple> #include <utility> @@ -107,6 +107,13 @@ const std::vector<std::string> CHECKLEVEL_DOC { * */ static constexpr int PRUNE_LOCK_BUFFER{10}; +/** + * Maximum number of seconds that the timestamp of the first + * block of a difficulty adjustment period is allowed to + * be earlier than the last block of the previous period (BIP94). + */ +static constexpr int64_t MAX_TIMEWARP = 600; + GlobalMutex g_best_block_mutex; std::condition_variable g_best_block_cv; uint256 g_best_block; @@ -134,6 +141,7 @@ const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locato bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, + ValidationCache& validation_cache, std::vector<CScriptCheck>* pvChecks = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -394,7 +402,8 @@ void Chainstate::MaybeUpdateMempoolForReorg( * */ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool, - unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip) + unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip, + ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) { AssertLockHeld(cs_main); @@ -426,7 +435,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS } // Call CheckInputScripts() to cache signature and script validity against current tip consensus rules. - return CheckInputScripts(tx, state, view, flags, /* cacheSigStore= */ true, /* cacheFullScriptStore= */ true, txdata); + return CheckInputScripts(tx, state, view, flags, /* cacheSigStore= */ true, /* cacheFullScriptStore= */ true, txdata, validation_cache); } namespace { @@ -716,6 +725,11 @@ private: return true; } + ValidationCache& GetValidationCache() + { + return m_active_chainstate.m_chainman.m_validation_cache; + } + private: CTxMemPool& m_pool; CCoinsViewCache m_view; @@ -1201,7 +1215,7 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn const CFeeRate package_feerate(m_subpackage.m_total_modified_fees, m_subpackage.m_total_vsize); if (package_feerate <= parent_feerate) { return package_state.Invalid(PackageValidationResult::PCKG_POLICY, - "package RBF failed: package feerate is less than parent feerate", + "package RBF failed: package feerate is less than or equal to parent feerate", strprintf("package feerate %s <= parent feerate is %s", package_feerate.ToString(), parent_feerate.ToString())); } @@ -1231,13 +1245,13 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) // Check input scripts and signatures. // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, ws.m_precomputed_txdata)) { + if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, ws.m_precomputed_txdata, GetValidationCache())) { // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we // need to turn both off, and compare against just turning off CLEANSTACK // to see if the failure is specifically due to witness validation. TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts - if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, ws.m_precomputed_txdata) && - !CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, ws.m_precomputed_txdata)) { + if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, ws.m_precomputed_txdata, GetValidationCache()) && + !CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, ws.m_precomputed_txdata, GetValidationCache())) { // Only the witness is missing, so the transaction itself may be fine. state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED, state.GetRejectReason(), state.GetDebugMessage()); @@ -1273,7 +1287,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) // transactions into the mempool can be exploited as a DoS attack. unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)}; if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, - ws.m_precomputed_txdata, m_active_chainstate.CoinsTip())) { + ws.m_precomputed_txdata, m_active_chainstate.CoinsTip(), GetValidationCache())) { LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString()); return Assume(false); } @@ -2084,29 +2098,23 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness; - return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error); + return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error); } -static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache; -static CSHA256 g_scriptExecutionCacheHasher; - -bool InitScriptExecutionCache(size_t max_size_bytes) +ValidationCache::ValidationCache(const size_t script_execution_cache_bytes, const size_t signature_cache_bytes) + : m_signature_cache{signature_cache_bytes} { // Setup the salted hasher uint256 nonce = GetRandHash(); // We want the nonce to be 64 bytes long to force the hasher to process // this chunk, which makes later hash computations more efficient. We // just write our 32-byte entropy twice to fill the 64 bytes. - g_scriptExecutionCacheHasher.Write(nonce.begin(), 32); - g_scriptExecutionCacheHasher.Write(nonce.begin(), 32); - - auto setup_results = g_scriptExecutionCache.setup_bytes(max_size_bytes); - if (!setup_results) return false; + m_script_execution_cache_hasher.Write(nonce.begin(), 32); + m_script_execution_cache_hasher.Write(nonce.begin(), 32); - const auto [num_elems, approx_size_bytes] = *setup_results; + const auto [num_elems, approx_size_bytes] = m_script_execution_cache.setup_bytes(script_execution_cache_bytes); LogPrintf("Using %zu MiB out of %zu MiB requested for script execution cache, able to store %zu elements\n", - approx_size_bytes >> 20, max_size_bytes >> 20, num_elems); - return true; + approx_size_bytes >> 20, script_execution_cache_bytes >> 20, num_elems); } /** @@ -2126,11 +2134,12 @@ bool InitScriptExecutionCache(size_t max_size_bytes) * Note that we may set state.reason to NOT_STANDARD for extra soft-fork flags in flags, block-checking * callers should probably reset it to CONSENSUS in such cases. * - * Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp + * Non-static (and redeclared) in src/test/txvalidationcache_tests.cpp */ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, + ValidationCache& validation_cache, std::vector<CScriptCheck>* pvChecks) { if (tx.IsCoinBase()) return true; @@ -2145,10 +2154,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, // properly commits to the scriptPubKey in the inputs view of that // transaction). uint256 hashCacheEntry; - CSHA256 hasher = g_scriptExecutionCacheHasher; + CSHA256 hasher = validation_cache.ScriptExecutionCacheHasher(); hasher.Write(UCharCast(tx.GetWitnessHash().begin()), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin()); AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks - if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) { + if (validation_cache.m_script_execution_cache.contains(hashCacheEntry, !cacheFullScriptStore)) { return true; } @@ -2175,7 +2184,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, // spent being checked as a part of CScriptCheck. // Verify signature - CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata); + CScriptCheck check(txdata.m_spent_outputs[i], tx, validation_cache.m_signature_cache, i, flags, cacheSigStore, &txdata); if (pvChecks) { pvChecks->emplace_back(std::move(check)); } else if (!check()) { @@ -2188,7 +2197,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, // splitting the network between upgraded and // non-upgraded nodes by banning CONSENSUS-failing // data providers. - CScriptCheck check2(txdata.m_spent_outputs[i], tx, i, + CScriptCheck check2(txdata.m_spent_outputs[i], tx, validation_cache.m_signature_cache, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata); if (check2()) return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); @@ -2209,7 +2218,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, if (cacheFullScriptStore && !pvChecks) { // We executed all of the provided scripts, and were told to // cache the result. Do so now. - g_scriptExecutionCache.insert(hashCacheEntry); + validation_cache.m_script_execution_cache.insert(hashCacheEntry); } return true; @@ -2280,8 +2289,8 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn // 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"))); + bool fEnforceBIP30 = !((pindex->nHeight==91722 && pindex->GetBlockHash() == uint256{"00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"}) || + (pindex->nHeight==91812 && pindex->GetBlockHash() == uint256{"00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"})); // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { @@ -2397,15 +2406,6 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Ch } -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() * can fail if those validity checks fail (among other reasons). */ @@ -2450,7 +2450,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); assert(hashPrevBlock == view.GetBestBlock()); - num_blocks_total++; + m_chainman.num_blocks_total++; // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) @@ -2492,11 +2492,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } const auto time_1{SteadyClock::now()}; - time_check += time_1 - time_start; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_check), + Ticks<MillisecondsDouble>(m_chainman.time_check) / m_chainman.num_blocks_total); // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. @@ -2594,11 +2594,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)}; const auto time_2{SteadyClock::now()}; - time_forks += time_2 - time_1; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_forks), + Ticks<MillisecondsDouble>(m_chainman.time_forks) / m_chainman.num_blocks_total); CBlockUndo blockundo; @@ -2667,7 +2667,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], parallel_script_checks ? &vChecks : nullptr)) { + if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, 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()); @@ -2685,12 +2685,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); } const auto time_3{SteadyClock::now()}; - time_connect += time_3 - time_2; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_connect), + Ticks<MillisecondsDouble>(m_chainman.time_connect) / m_chainman.num_blocks_total); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, params.GetConsensus()); if (block.vtx[0]->GetValueOut() > blockReward) { @@ -2703,12 +2703,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "block-validation-failed"); } const auto time_4{SteadyClock::now()}; - time_verify += time_4 - time_2; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_verify), + Ticks<MillisecondsDouble>(m_chainman.time_verify) / m_chainman.num_blocks_total); if (fJustCheck) return true; @@ -2718,11 +2718,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } const auto time_5{SteadyClock::now()}; - time_undo += time_5 - time_4; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_undo), + Ticks<MillisecondsDouble>(m_chainman.time_undo) / m_chainman.num_blocks_total); if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) { pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); @@ -2733,11 +2733,11 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, view.SetBestBlock(pindex->GetBlockHash()); const auto time_6{SteadyClock::now()}; - time_index += time_6 - time_5; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_index), + Ticks<MillisecondsDouble>(m_chainman.time_index) / m_chainman.num_blocks_total); TRACE6(validation, block_connected, block_hash.data(), @@ -2909,7 +2909,7 @@ bool Chainstate::FlushStateToDisk( return FatalError(m_chainman.GetNotifications(), state, _("Disk space is too low!")); } // Flush the chainstate (which may refer to block index entries). - const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fFlushForPrune}; + const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical}; if (empty_cache ? !CoinsTip().Flush() : !CoinsTip().Sync()) { return FatalError(m_chainman.GetNotifications(), state, _("Failed to write to coin database.")); } @@ -2963,7 +2963,7 @@ static void UpdateTipLog( LogPrintf("%s%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", prefix, func_name, tip->GetBlockHash().ToString(), tip->nHeight, tip->nVersion, - log(tip->nChainWork.getdouble()) / log(2.0), (unsigned long)tip->nChainTx, + log(tip->nChainWork.getdouble()) / log(2.0), tip->m_chain_tx_count, FormatISO8601DateTime(tip->GetBlockTime()), GuessVerificationProgress(params.TxData(), tip), coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)), @@ -3095,11 +3095,6 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra return true; } -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; std::shared_ptr<const CBlock> pblock; @@ -3186,31 +3181,31 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, return false; } time_3 = SteadyClock::now(); - time_connect_total += time_3 - time_2; - assert(num_blocks_total > 0); + m_chainman.time_connect_total += time_3 - time_2; + assert(m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_connect_total), + Ticks<MillisecondsDouble>(m_chainman.time_connect_total) / m_chainman.num_blocks_total); bool flushed = view.Flush(); assert(flushed); } const auto time_4{SteadyClock::now()}; - time_flush += time_4 - time_3; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_flush), + Ticks<MillisecondsDouble>(m_chainman.time_flush) / m_chainman.num_blocks_total); // Write the chain state to disk, if necessary. if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) { return false; } const auto time_5{SteadyClock::now()}; - time_chainstate += time_5 - time_4; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_chainstate), + Ticks<MillisecondsDouble>(m_chainman.time_chainstate) / m_chainman.num_blocks_total); // Remove conflicting transactions from the mempool.; if (m_mempool) { m_mempool->removeForBlock(blockConnecting.vtx, pindexNew->nHeight); @@ -3221,16 +3216,16 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, UpdateTip(pindexNew); const auto time_6{SteadyClock::now()}; - time_post_connect += time_6 - time_5; - time_total += time_6 - time_1; + m_chainman.time_post_connect += time_6 - time_5; + m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_post_connect), + Ticks<MillisecondsDouble>(m_chainman.time_post_connect) / m_chainman.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); + Ticks<SecondsDouble>(m_chainman.time_total), + Ticks<MillisecondsDouble>(m_chainman.time_total) / m_chainman.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). @@ -3369,7 +3364,7 @@ bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* nHeight = nTargetHeight; // Connect new blocks. - for (CBlockIndex* pindexConnect : reverse_iterate(vpindexToConnect)) { + for (CBlockIndex* pindexConnect : vpindexToConnect | std::views::reverse) { if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) { if (state.IsInvalid()) { // The block violates a consensus rule. @@ -3417,25 +3412,24 @@ static SynchronizationState GetSynchronizationState(bool init, bool blockfiles_i return SynchronizationState::INIT_DOWNLOAD; } -static bool NotifyHeaderTip(ChainstateManager& chainman) LOCKS_EXCLUDED(cs_main) +bool ChainstateManager::NotifyHeaderTip() { bool fNotify = false; bool fInitialBlockDownload = false; - static CBlockIndex* pindexHeaderOld = nullptr; CBlockIndex* pindexHeader = nullptr; { - LOCK(cs_main); - pindexHeader = chainman.m_best_header; + LOCK(GetMutex()); + pindexHeader = m_best_header; - if (pindexHeader != pindexHeaderOld) { + if (pindexHeader != m_last_notified_header) { fNotify = true; - fInitialBlockDownload = chainman.IsInitialBlockDownload(); - pindexHeaderOld = pindexHeader; + fInitialBlockDownload = IsInitialBlockDownload(); + m_last_notified_header = pindexHeader; } } - // Send block tip changed notifications without cs_main + // Send block tip changed notifications without the lock held if (fNotify) { - chainman.GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload, chainman.m_blockman.m_blockfiles_indexed), pindexHeader->nHeight, pindexHeader->nTime, false); + GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload, m_blockman.m_blockfiles_indexed), pindexHeader->nHeight, pindexHeader->nTime, false); } return fNotify; } @@ -3486,6 +3480,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< { LOCK(cs_main); + { // Lock transaction pool for at least as long as it takes for connectTrace to be consumed LOCK(MempoolMutex()); const bool was_in_ibd = m_chainman.IsInitialBlockDownload(); @@ -3562,7 +3557,12 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< break; } } - } + } // release MempoolMutex + // Notify external listeners about the new tip, even if pindexFork == pindexNewTip. + if (m_chainman.m_options.signals && this == &m_chainman.ActiveChainstate()) { + m_chainman.m_options.signals->ActiveTipChange(*Assert(pindexNewTip), m_chainman.IsInitialBlockDownload()); + } + } // release cs_main // When we reach this point, we switched to a new tip (stored in pindexNewTip). if (exited_ibd) { @@ -3781,6 +3781,12 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde // distinguish user-initiated invalidateblock changes from other // changes. (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_blockfiles_indexed), *to_mark_failed->pprev); + + // Fire ActiveTipChange now for the current chain tip to make sure clients are notified. + // ActivateBestChain may call this as well, but not necessarily. + if (m_chainman.m_options.signals) { + m_chainman.m_options.signals->ActiveTipChange(*Assert(m_chain.Tip()), m_chainman.IsInitialBlockDownload()); + } } return true; } @@ -3847,17 +3853,17 @@ void ChainstateManager::ReceivedBlockTransactions(const CBlock& block, CBlockInd { AssertLockHeld(cs_main); pindexNew->nTx = block.vtx.size(); - // Typically nChainTx will be 0 at this point, but it can be nonzero if this + // Typically m_chain_tx_count will be 0 at this point, but it can be nonzero if this // is a pruned block which is being downloaded again, or if this is an - // assumeutxo snapshot block which has a hardcoded nChainTx value from the + // assumeutxo snapshot block which has a hardcoded m_chain_tx_count value from the // snapshot metadata. If the pindex is not the snapshot block and the - // nChainTx value is not zero, assert that value is actually correct. - auto prev_tx_sum = [](CBlockIndex& block) { return block.nTx + (block.pprev ? block.pprev->nChainTx : 0); }; - if (!Assume(pindexNew->nChainTx == 0 || pindexNew->nChainTx == prev_tx_sum(*pindexNew) || + // m_chain_tx_count value is not zero, assert that value is actually correct. + auto prev_tx_sum = [](CBlockIndex& block) { return block.nTx + (block.pprev ? block.pprev->m_chain_tx_count : 0); }; + if (!Assume(pindexNew->m_chain_tx_count == 0 || pindexNew->m_chain_tx_count == prev_tx_sum(*pindexNew) || pindexNew == GetSnapshotBaseBlock())) { - LogWarning("Internal bug detected: block %d has unexpected nChainTx %i that should be %i (%s %s). Please report this issue here: %s\n", - pindexNew->nHeight, pindexNew->nChainTx, prev_tx_sum(*pindexNew), PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); - pindexNew->nChainTx = 0; + LogWarning("Internal bug detected: block %d has unexpected m_chain_tx_count %i that should be %i (%s %s). Please report this issue here: %s\n", + pindexNew->nHeight, pindexNew->m_chain_tx_count, prev_tx_sum(*pindexNew), PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); + pindexNew->m_chain_tx_count = 0; } pindexNew->nFile = pos.nFile; pindexNew->nDataPos = pos.nPos; @@ -3878,15 +3884,15 @@ void ChainstateManager::ReceivedBlockTransactions(const CBlock& block, CBlockInd while (!queue.empty()) { CBlockIndex *pindex = queue.front(); queue.pop_front(); - // Before setting nChainTx, assert that it is 0 or already set to + // Before setting m_chain_tx_count, assert that it is 0 or already set to // the correct value. This assert will fail after receiving the // assumeutxo snapshot block if assumeutxo snapshot metadata has an - // incorrect hardcoded AssumeutxoData::nChainTx value. - if (!Assume(pindex->nChainTx == 0 || pindex->nChainTx == prev_tx_sum(*pindex))) { - LogWarning("Internal bug detected: block %d has unexpected nChainTx %i that should be %i (%s %s). Please report this issue here: %s\n", - pindex->nHeight, pindex->nChainTx, prev_tx_sum(*pindex), PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); + // incorrect hardcoded AssumeutxoData::m_chain_tx_count value. + if (!Assume(pindex->m_chain_tx_count == 0 || pindex->m_chain_tx_count == prev_tx_sum(*pindex))) { + LogWarning("Internal bug detected: block %d has unexpected m_chain_tx_count %i that should be %i (%s %s). Please report this issue here: %s\n", + pindex->nHeight, pindex->m_chain_tx_count, prev_tx_sum(*pindex), PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); } - pindex->nChainTx = prev_tx_sum(*pindex); + pindex->m_chain_tx_count = prev_tx_sum(*pindex); pindex->nSequenceId = nBlockSequenceId++; for (Chainstate *c : GetAll()) { c->TryAddBlockIndexCandidate(pindex); @@ -4183,6 +4189,18 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", "block's timestamp is too early"); + // Testnet4 only: Check timestamp against prev for difficulty-adjustment + // blocks to prevent timewarp attacks (see https://github.com/bitcoin/bitcoin/pull/15482). + if (consensusParams.enforce_BIP94) { + // Check timestamp for the first block of each difficulty adjustment + // interval, except the genesis block. + if (nHeight % consensusParams.DifficultyAdjustmentInterval() == 0) { + if (block.GetBlockTime() < pindexPrev->GetBlockTime() - MAX_TIMEWARP) { + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-timewarp-attack", "block's timestamp is too early on diff adjustment block"); + } + } + } + // Check timestamp if (block.Time() > NodeClock::now() + std::chrono::seconds{MAX_FUTURE_BLOCK_TIME}) { return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future"); @@ -4391,7 +4409,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& } } } - if (NotifyHeaderTip(*this)) { + if (NotifyHeaderTip()) { if (IsInitialBlockDownload() && ppindex && *ppindex) { const CBlockIndex& last_accepted{**ppindex}; int64_t blocks_left{(NodeClock::now() - last_accepted.Time()) / GetConsensus().PowTargetSpacing()}; @@ -4562,7 +4580,7 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo } } - NotifyHeaderTip(*this); + NotifyHeaderTip(); BlockValidationState state; // Only used to report errors, not invalidity - ignore it if (!ActiveChainstate().ActivateBestChain(state, block)) { @@ -5139,7 +5157,7 @@ void ChainstateManager::LoadExternalBlockFile( } } - NotifyHeaderTip(*this); + NotifyHeaderTip(); if (!blocks_with_unknown_parent) continue; @@ -5165,7 +5183,7 @@ void ChainstateManager::LoadExternalBlockFile( } range.first++; blocks_with_unknown_parent->erase(it); - NotifyHeaderTip(*this); + NotifyHeaderTip(); } } } catch (const std::exception& e) { @@ -5193,7 +5211,7 @@ bool ChainstateManager::ShouldCheckBlockIndex() const { // Assert to verify Flatten() has been called. if (!*Assert(m_options.check_block_index)) return false; - if (GetRand(*m_options.check_block_index) >= 1) return false; + if (FastRandomContext().randrange(*m_options.check_block_index) >= 1) return false; return true; } @@ -5334,17 +5352,17 @@ void ChainstateManager::CheckBlockIndex() // Checks for not-invalid blocks. assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. } - // Make sure nChainTx sum is correctly computed. + // Make sure m_chain_tx_count sum is correctly computed. if (!pindex->pprev) { - // If no previous block, nTx and nChainTx must be the same. - assert(pindex->nChainTx == pindex->nTx); - } else if (pindex->pprev->nChainTx > 0 && pindex->nTx > 0) { - // If previous nChainTx is set and number of transactions in block is known, sum must be set. - assert(pindex->nChainTx == pindex->nTx + pindex->pprev->nChainTx); + // If no previous block, nTx and m_chain_tx_count must be the same. + assert(pindex->m_chain_tx_count == pindex->nTx); + } else if (pindex->pprev->m_chain_tx_count > 0 && pindex->nTx > 0) { + // If previous m_chain_tx_count is set and number of transactions in block is known, sum must be set. + assert(pindex->m_chain_tx_count == pindex->nTx + pindex->pprev->m_chain_tx_count); } else { - // Otherwise nChainTx should only be set if this is a snapshot + // Otherwise m_chain_tx_count should only be set if this is a snapshot // block, and must be set if it is. - assert((pindex->nChainTx != 0) == (pindex == snap_base)); + assert((pindex->m_chain_tx_count != 0) == (pindex == snap_base)); } // Chainstate-specific checks on setBlockIndexCandidates @@ -5373,7 +5391,7 @@ void ChainstateManager::CheckBlockIndex() // and the transactions were not pruned (pindexFirstMissing // is null), it is a potential candidate. The check // excludes pruned blocks, because if any blocks were - // pruned between pindex the current chain tip, pindex will + // pruned between pindex and the current chain tip, pindex will // only temporarily be added to setBlockIndexCandidates, // before being moved to m_blocks_unlinked. This check // could be improved to verify that if all blocks between @@ -5549,13 +5567,13 @@ bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) } //! Guess how far we are in the verification process at the given block index -//! require cs_main if pindex has not been validated yet (because nChainTx might be unset) +//! require cs_main if pindex has not been validated yet (because m_chain_tx_count might be unset) double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) { if (pindex == nullptr) return 0.0; - if (!Assume(pindex->nChainTx > 0)) { - LogWarning("Internal bug detected: block %d has unset nChainTx (%s %s). Please report this issue here: %s\n", + if (!Assume(pindex->m_chain_tx_count > 0)) { + LogWarning("Internal bug detected: block %d has unset m_chain_tx_count (%s %s). Please report this issue here: %s\n", pindex->nHeight, PACKAGE_NAME, FormatFullVersion(), PACKAGE_BUGREPORT); return 0.0; } @@ -5564,13 +5582,13 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin double fTxTotal; - if (pindex->nChainTx <= data.nTxCount) { - fTxTotal = data.nTxCount + (nNow - data.nTime) * data.dTxRate; + if (pindex->m_chain_tx_count <= data.tx_count) { + fTxTotal = data.tx_count + (nNow - data.nTime) * data.dTxRate; } else { - fTxTotal = pindex->nChainTx + (nNow - pindex->GetBlockTime()) * data.dTxRate; + fTxTotal = pindex->m_chain_tx_count + (nNow - pindex->GetBlockTime()) * data.dTxRate; } - return std::min<double>(pindex->nChainTx / fTxTotal, 1.0); + return std::min<double>(pindex->m_chain_tx_count / fTxTotal, 1.0); } std::optional<uint256> ChainstateManager::SnapshotBlockhash() const @@ -5646,43 +5664,48 @@ Chainstate& ChainstateManager::InitializeChainstate(CTxMemPool* mempool) return destroyed && !fs::exists(db_path); } -util::Result<void> ChainstateManager::ActivateSnapshot( +util::Result<CBlockIndex*> ChainstateManager::ActivateSnapshot( AutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory) { uint256 base_blockhash = metadata.m_base_blockhash; - int base_blockheight = metadata.m_base_blockheight; if (this->SnapshotBlockhash()) { - return util::Error{_("Can't activate a snapshot-based chainstate more than once")}; + return util::Error{Untranslated("Can't activate a snapshot-based chainstate more than once")}; } + CBlockIndex* snapshot_start_block{}; + { LOCK(::cs_main); if (!GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) { auto available_heights = GetParams().GetAvailableSnapshotHeights(); std::string heights_formatted = util::Join(available_heights, ", ", [&](const auto& i) { return util::ToString(i); }); - return util::Error{strprintf(_("assumeutxo block hash in snapshot metadata not recognized (hash: %s, height: %s). The following snapshot heights are available: %s."), + return util::Error{strprintf(Untranslated("assumeutxo block hash in snapshot metadata not recognized (hash: %s). The following snapshot heights are available: %s"), base_blockhash.ToString(), - base_blockheight, heights_formatted)}; } - CBlockIndex* snapshot_start_block = m_blockman.LookupBlockIndex(base_blockhash); + snapshot_start_block = m_blockman.LookupBlockIndex(base_blockhash); if (!snapshot_start_block) { - return util::Error{strprintf(_("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call loadtxoutset again."), + return util::Error{strprintf(Untranslated("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call loadtxoutset again"), base_blockhash.ToString())}; } bool start_block_invalid = snapshot_start_block->nStatus & BLOCK_FAILED_MASK; if (start_block_invalid) { - return util::Error{strprintf(_("The base block header (%s) is part of an invalid chain."), base_blockhash.ToString())}; + return util::Error{strprintf(Untranslated("The base block header (%s) is part of an invalid chain"), base_blockhash.ToString())}; + } + + if (!m_best_header || m_best_header->GetAncestor(snapshot_start_block->nHeight) != snapshot_start_block) { + return util::Error{Untranslated("A forked headers-chain with more work than the chain with the snapshot base block header exists. Please proceed to sync without AssumeUtxo.")}; } - if (Assert(m_active_chainstate->GetMempool())->size() > 0) { - return util::Error{_("Can't activate a snapshot when mempool not empty.")}; + auto mempool{m_active_chainstate->GetMempool()}; + if (mempool && mempool->size() > 0) { + return util::Error{Untranslated("Can't activate a snapshot when mempool not empty")}; } } @@ -5731,7 +5754,7 @@ util::Result<void> ChainstateManager::ActivateSnapshot( static_cast<size_t>(current_coinstip_cache_size * SNAPSHOT_CACHE_PERC)); } - auto cleanup_bad_snapshot = [&](const char* reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + auto cleanup_bad_snapshot = [&](bilingual_str reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { this->MaybeRebalanceCaches(); // PopulateAndValidateSnapshot can return (in error) before the leveldb datadir @@ -5747,12 +5770,12 @@ util::Result<void> ChainstateManager::ActivateSnapshot( "Manually remove it before restarting.\n"), fs::PathToString(*snapshot_datadir))); } } - return util::Error{_(reason)}; + return util::Error{std::move(reason)}; }; - if (!this->PopulateAndValidateSnapshot(*snapshot_chainstate, coins_file, metadata)) { + if (auto res{this->PopulateAndValidateSnapshot(*snapshot_chainstate, coins_file, metadata)}; !res) { LOCK(::cs_main); - return cleanup_bad_snapshot("population failed"); + return cleanup_bad_snapshot(strprintf(Untranslated("Population failed: %s"), util::ErrorString(res))); } LOCK(::cs_main); // cs_main required for rest of snapshot activation. @@ -5761,13 +5784,13 @@ util::Result<void> ChainstateManager::ActivateSnapshot( // work chain than the active chainstate; a user could have loaded a snapshot // very late in the IBD process, and we wouldn't want to load a useless chainstate. if (!CBlockIndexWorkComparator()(ActiveTip(), snapshot_chainstate->m_chain.Tip())) { - return cleanup_bad_snapshot("work does not exceed active chainstate"); + return cleanup_bad_snapshot(Untranslated("work does not exceed active chainstate")); } // If not in-memory, persist the base blockhash for use during subsequent // initialization. if (!in_memory) { if (!node::WriteSnapshotBaseBlockhash(*snapshot_chainstate)) { - return cleanup_bad_snapshot("could not write base blockhash"); + return cleanup_bad_snapshot(Untranslated("could not write base blockhash")); } } @@ -5790,7 +5813,7 @@ util::Result<void> ChainstateManager::ActivateSnapshot( m_snapshot_chainstate->CoinsTip().DynamicMemoryUsage() / (1000 * 1000)); this->MaybeRebalanceCaches(); - return {}; + return snapshot_start_block; } static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_loaded) @@ -5817,7 +5840,7 @@ static void SnapshotUTXOHashBreakpoint(const util::SignalInterrupt& interrupt) if (interrupt) throw StopHashingException(); } -bool ChainstateManager::PopulateAndValidateSnapshot( +util::Result<void> ChainstateManager::PopulateAndValidateSnapshot( Chainstate& snapshot_chainstate, AutoFile& coins_file, const SnapshotMetadata& metadata) @@ -5833,18 +5856,16 @@ bool ChainstateManager::PopulateAndValidateSnapshot( if (!snapshot_start_block) { // Needed for ComputeUTXOStats to determine the // height and to avoid a crash when base_blockhash.IsNull() - LogPrintf("[snapshot] Did not find snapshot start blockheader %s\n", - base_blockhash.ToString()); - return false; + return util::Error{strprintf(Untranslated("Did not find snapshot start blockheader %s"), + base_blockhash.ToString())}; } int base_height = snapshot_start_block->nHeight; const auto& maybe_au_data = GetParams().AssumeutxoForHeight(base_height); if (!maybe_au_data) { - LogPrintf("[snapshot] assumeutxo height in snapshot metadata not recognized " - "(%d) - refusing to load snapshot\n", base_height); - return false; + return util::Error{strprintf(Untranslated("Assumeutxo height in snapshot metadata not recognized " + "(%d) - refusing to load snapshot"), base_height)}; } const AssumeutxoData& au_data = *maybe_au_data; @@ -5853,8 +5874,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // ActivateSnapshot(), but is done so that we avoid doing the long work of staging // a snapshot that isn't actually usable. if (WITH_LOCK(::cs_main, return !CBlockIndexWorkComparator()(ActiveTip(), snapshot_start_block))) { - LogPrintf("[snapshot] activation failed - work does not exceed active chainstate\n"); - return false; + return util::Error{Untranslated("Work does not exceed active chainstate")}; } const uint64_t coins_count = metadata.m_coins_count; @@ -5871,8 +5891,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( coins_per_txid = ReadCompactSize(coins_file); if (coins_per_txid > coins_left) { - LogPrintf("[snapshot] mismatch in coins count in snapshot metadata and actual snapshot data\n"); - return false; + return util::Error{Untranslated("Mismatch in coins count in snapshot metadata and actual snapshot data")}; } for (size_t i = 0; i < coins_per_txid; i++) { @@ -5884,14 +5903,12 @@ bool ChainstateManager::PopulateAndValidateSnapshot( if (coin.nHeight > base_height || outpoint.n >= std::numeric_limits<decltype(outpoint.n)>::max() // Avoid integer wrap-around in coinstats.cpp:ApplyHash ) { - LogPrintf("[snapshot] bad snapshot data after deserializing %d coins\n", - coins_count - coins_left); - return false; + return util::Error{strprintf(Untranslated("Bad snapshot data after deserializing %d coins"), + coins_count - coins_left)}; } if (!MoneyRange(coin.out.nValue)) { - LogPrintf("[snapshot] bad snapshot data after deserializing %d coins - bad tx out value\n", - coins_count - coins_left); - return false; + return util::Error{strprintf(Untranslated("Bad snapshot data after deserializing %d coins - bad tx out value"), + coins_count - coins_left)}; } coins_cache.EmplaceCoinInternalDANGER(std::move(outpoint), std::move(coin)); @@ -5911,7 +5928,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // means <5MB of memory imprecision. if (coins_processed % 120000 == 0) { if (m_interrupt) { - return false; + return util::Error{Untranslated("Aborting after an interrupt was requested")}; } const auto snapshot_cache_state = WITH_LOCK(::cs_main, @@ -5929,9 +5946,8 @@ bool ChainstateManager::PopulateAndValidateSnapshot( } } } catch (const std::ios_base::failure&) { - LogPrintf("[snapshot] bad snapshot format or truncated snapshot after deserializing %d coins\n", - coins_processed); - return false; + return util::Error{strprintf(Untranslated("Bad snapshot format or truncated snapshot after deserializing %d coins"), + coins_processed)}; } } @@ -5951,9 +5967,8 @@ bool ChainstateManager::PopulateAndValidateSnapshot( out_of_coins = true; } if (!out_of_coins) { - LogPrintf("[snapshot] bad snapshot - coins left over after deserializing %d coins\n", - coins_count); - return false; + return util::Error{strprintf(Untranslated("Bad snapshot - coins left over after deserializing %d coins"), + coins_count)}; } LogPrintf("[snapshot] loaded %d (%.2f MB) coins from snapshot %s\n", @@ -5976,18 +5991,16 @@ bool ChainstateManager::PopulateAndValidateSnapshot( maybe_stats = ComputeUTXOStats( CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); }); } catch (StopHashingException const&) { - return false; + return util::Error{Untranslated("Aborting after an interrupt was requested")}; } if (!maybe_stats.has_value()) { - LogPrintf("[snapshot] failed to generate coins stats\n"); - return false; + return util::Error{Untranslated("Failed to generate coins stats")}; } // Assert that the deserialized chainstate contents match the expected assumeutxo value. if (AssumeutxoHash{maybe_stats->hashSerialized} != au_data.hash_serialized) { - LogPrintf("[snapshot] bad snapshot content hash: expected %s, got %s\n", - au_data.hash_serialized.ToString(), maybe_stats->hashSerialized.ToString()); - return false; + return util::Error{strprintf(Untranslated("Bad snapshot content hash: expected %s, got %s"), + au_data.hash_serialized.ToString(), maybe_stats->hashSerialized.ToString())}; } snapshot_chainstate.m_chain.SetTip(*snapshot_start_block); @@ -6022,12 +6035,12 @@ bool ChainstateManager::PopulateAndValidateSnapshot( assert(index); assert(index == snapshot_start_block); - index->nChainTx = au_data.nChainTx; + index->m_chain_tx_count = au_data.m_chain_tx_count; snapshot_chainstate.setBlockIndexCandidates.insert(snapshot_start_block); LogPrintf("[snapshot] validated snapshot (%.2f MB)\n", coins_cache.DynamicMemoryUsage() / (1000 * 1000)); - return true; + return {}; } // Currently, this function holds cs_main for its duration, which could be for @@ -6248,7 +6261,8 @@ ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Opt : m_script_check_queue{/*batch_size=*/128, options.worker_threads_num}, m_interrupt{interrupt}, m_options{Flatten(std::move(options))}, - m_blockman{interrupt, std::move(blockman_options)} + m_blockman{interrupt, std::move(blockman_options)}, + m_validation_cache{m_options.script_execution_cache_bytes, m_options.signature_cache_bytes} { } @@ -6295,14 +6309,14 @@ Chainstate& ChainstateManager::ActivateExistingSnapshot(uint256 base_blockhash) 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")); + return (block_index.nHeight==91842 && block_index.GetBlockHash() == uint256{"00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"}) || + (block_index.nHeight==91880 && block_index.GetBlockHash() == uint256{"00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"}); } 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")); + return (block_index.nHeight==91722 && block_index.GetBlockHash() == uint256{"00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"}) || + (block_index.nHeight==91812 && block_index.GetBlockHash() == uint256{"00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"}); } static fs::path GetSnapshotCoinsDBPath(Chainstate& cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) diff --git a/src/validation.h b/src/validation.h index 2f5f2e2b95..f905d6e624 100644 --- a/src/validation.h +++ b/src/validation.h @@ -10,9 +10,10 @@ #include <attributes.h> #include <chain.h> #include <checkqueue.h> -#include <kernel/chain.h> #include <consensus/amount.h> +#include <cuckoocache.h> #include <deploymentstatus.h> +#include <kernel/chain.h> #include <kernel/chainparams.h> #include <kernel/chainstatemanager_opts.h> #include <kernel/cs_main.h> // IWYU pragma: export @@ -21,6 +22,7 @@ #include <policy/packages.h> #include <policy/policy.h> #include <script/script_error.h> +#include <script/sigcache.h> #include <sync.h> #include <txdb.h> #include <txmempool.h> // For CTxMemPool::cs @@ -340,10 +342,11 @@ private: bool cacheStore; ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR}; PrecomputedTransactionData *txdata; + SignatureCache* m_signature_cache; public: - CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : - m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { } + CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : + m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { } CScriptCheck(const CScriptCheck&) = delete; CScriptCheck& operator=(const CScriptCheck&) = delete; @@ -360,8 +363,28 @@ static_assert(std::is_nothrow_move_assignable_v<CScriptCheck>); static_assert(std::is_nothrow_move_constructible_v<CScriptCheck>); static_assert(std::is_nothrow_destructible_v<CScriptCheck>); -/** Initializes the script-execution cache */ -[[nodiscard]] bool InitScriptExecutionCache(size_t max_size_bytes); +/** + * Convenience class for initializing and passing the script execution cache + * and signature cache. + */ +class ValidationCache +{ +private: + //! Pre-initialized hasher to avoid having to recreate it for every hash calculation. + CSHA256 m_script_execution_cache_hasher; + +public: + CuckooCache::cache<uint256, SignatureCacheHasher> m_script_execution_cache; + SignatureCache m_signature_cache; + + ValidationCache(size_t script_execution_cache_bytes, size_t signature_cache_bytes); + + ValidationCache(const ValidationCache&) = delete; + ValidationCache& operator=(const ValidationCache&) = delete; + + //! Return a copy of the pre-initialized hasher. + CSHA256 ScriptExecutionCacheHasher() const { return m_script_execution_cache_hasher; } +}; /** Functions for validating blocks and updating the block tree */ @@ -796,7 +819,6 @@ private: friend ChainstateManager; }; - enum class SnapshotCompletionResult { SUCCESS, SKIPPED, @@ -884,6 +906,11 @@ private: CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr}; + /** The last header for which a headerTip notification was issued. */ + CBlockIndex* m_last_notified_header GUARDED_BY(GetMutex()){nullptr}; + + bool NotifyHeaderTip() LOCKS_EXCLUDED(GetMutex()); + //! Internal helper for ActivateSnapshot(). //! //! De-serialization of a snapshot that is created with @@ -891,7 +918,7 @@ private: //! To reduce space the serialization format of the snapshot avoids //! duplication of tx hashes. The code takes advantage of the guarantee by //! leveldb that keys are lexicographically sorted. - [[nodiscard]] bool PopulateAndValidateSnapshot( + [[nodiscard]] util::Result<void> PopulateAndValidateSnapshot( Chainstate& snapshot_chainstate, AutoFile& coins_file, const node::SnapshotMetadata& metadata); @@ -927,6 +954,21 @@ private: //! A queue for script verifications that have to be performed by worker threads. CCheckQueue<CScriptCheck> m_script_check_queue; + //! Timers and counters used for benchmarking validation in both background + //! and active chainstates. + SteadyClock::duration GUARDED_BY(::cs_main) time_check{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_forks{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_connect{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_verify{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_undo{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_index{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_total{}; + int64_t GUARDED_BY(::cs_main) num_blocks_total{0}; + SteadyClock::duration GUARDED_BY(::cs_main) time_connect_total{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_flush{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_chainstate{}; + SteadyClock::duration GUARDED_BY(::cs_main) time_post_connect{}; + public: using Options = kernel::ChainstateManagerOpts; @@ -970,6 +1012,8 @@ public: //! chainstate to avoid duplicating block metadata. node::BlockManager m_blockman; + ValidationCache m_validation_cache; + /** * Whether initial block download has ended and IsInitialBlockDownload * should return false from now on. @@ -1050,11 +1094,10 @@ public: //! - Verify that the hash of the resulting coinsdb matches the expected hash //! per assumeutxo chain parameters. //! - Wait for our headers chain to include the base block of the snapshot. - //! - "Fast forward" the tip of the new chainstate to the base of the snapshot, - //! faking nTx* block index data along the way. + //! - "Fast forward" the tip of the new chainstate to the base of the snapshot. //! - Move the new chainstate to `m_snapshot_chainstate` and make it our //! ChainstateActive(). - [[nodiscard]] util::Result<void> ActivateSnapshot( + [[nodiscard]] util::Result<CBlockIndex*> ActivateSnapshot( AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory); //! Once the background validation chainstate has reached the height which diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 813fde109c..0ebcf926ca 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -95,7 +95,7 @@ public: ValidationSignals::ValidationSignals(std::unique_ptr<util::TaskRunnerInterface> task_runner) : m_internals{std::make_unique<ValidationSignalsImpl>(std::move(task_runner))} {} -ValidationSignals::~ValidationSignals() {} +ValidationSignals::~ValidationSignals() = default; void ValidationSignals::FlushBackgroundCallbacks() { @@ -183,6 +183,12 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo fInitialDownload); } +void ValidationSignals::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd) +{ + LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip.GetBlockHash().ToString(), new_tip.nHeight); + m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); }); +} + void ValidationSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence) { auto event = [tx, mempool_sequence, this] { diff --git a/src/validationinterface.h b/src/validationinterface.h index 6f49a73c93..3cf75aa210 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -62,6 +62,10 @@ protected: */ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {} /** + * Notifies listeners any time the block chain tip changes, synchronously. + */ + virtual void ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd) {}; + /** * Notifies listeners of a transaction having been added to mempool. * * Called on a background thread. @@ -214,6 +218,7 @@ public: void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main); void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); + void ActiveTipChange(const CBlockIndex&, bool); void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence); void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence); void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>&, unsigned int nBlockHeight); diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index b2f813383d..d36314312a 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -115,6 +115,8 @@ public: std::optional<uint32_t> m_locktime; //! Version std::optional<uint32_t> m_version; + //! Caps weight of resulting tx + std::optional<int> m_max_tx_weight{std::nullopt}; CCoinControl(); diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index f1706b6800..b6fee37c95 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -84,14 +84,14 @@ struct { * bound of the range. * @param const CAmount& cost_of_change This is the cost of creating and spending a change output. * This plus selection_target is the upper bound of the range. - * @param int max_weight The maximum weight available for the input set. + * @param int max_selection_weight The maximum allowed weight for a selection result to be valid. * @returns The result of this coin selection algorithm, or std::nullopt */ static const size_t TOTAL_TRIES = 100000; util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change, - int max_weight) + int max_selection_weight) { SelectionResult result(selection_target, SelectionAlgorithm::BNB); CAmount curr_value = 0; @@ -128,7 +128,7 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool curr_value > selection_target + cost_of_change || // Selected value is out of range, go back and try other branch (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_selection_weight > max_weight) { // Exceeding weight for standard tx, cannot find more solutions by adding more inputs + } else if (curr_selection_weight > max_selection_weight) { // Selected UTXOs weight exceeds the maximum weight allowed, cannot find more solutions by adding more inputs max_tx_weight_exceeded = true; // at least one selection attempt exceeded the max weight backtrack = true; } else if (curr_value >= selection_target) { // Selected value is within range @@ -319,10 +319,10 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool * group with multiple as a heavier UTXO with the combined amount here.) * @param const CAmount& selection_target This is the minimum amount that we need for the transaction without considering change. * @param const CAmount& change_target The minimum budget for creating a change output, by which we increase the selection_target. - * @param int max_weight The maximum permitted weight for the input set. + * @param int max_selection_weight The maximum allowed weight for a selection result to be valid. * @returns The result of this coin selection algorithm, or std::nullopt */ -util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight) +util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_selection_weight) { std::sort(utxo_pool.begin(), utxo_pool.end(), descending_effval_weight); // The sum of UTXO amounts after this UTXO index, e.g. lookahead[5] = Σ(UTXO[6+].amount) @@ -359,7 +359,7 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c // The weight of the currently selected input set, and the weight of the best selection int curr_weight = 0; - int best_selection_weight = max_weight; // Tie is fine, because we prefer lower selection amount + int best_selection_weight = max_selection_weight; // Tie is fine, because we prefer lower selection amount // Whether the input sets generated during this search have exceeded the maximum transaction weight at any point bool max_tx_weight_exceeded = false; @@ -436,8 +436,8 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c // Insufficient funds with lookahead: CUT should_cut = true; } else if (curr_weight > best_selection_weight) { - // best_selection_weight is initialized to max_weight - if (curr_weight > max_weight) max_tx_weight_exceeded = true; + // best_selection_weight is initialized to max_selection_weight + if (curr_weight > max_selection_weight) max_tx_weight_exceeded = true; // Worse weight than best solution. More UTXOs only increase weight: // CUT if last selected group had minimal weight, else SHIFT if (utxo_pool[curr_tail].m_weight <= min_tail_weight[curr_tail]) { @@ -535,7 +535,7 @@ public: }; util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng, - int max_weight) + int max_selection_weight) { SelectionResult result(target_value, SelectionAlgorithm::SRD); std::priority_queue<OutputGroup, std::vector<OutputGroup>, MinOutputGroupComparator> heap; @@ -549,7 +549,7 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx std::vector<size_t> indexes; indexes.resize(utxo_pool.size()); std::iota(indexes.begin(), indexes.end(), 0); - Shuffle(indexes.begin(), indexes.end(), rng); + std::shuffle(indexes.begin(), indexes.end(), rng); CAmount selected_eff_value = 0; int weight = 0; @@ -565,14 +565,14 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx // If the selection weight exceeds the maximum allowed size, remove the least valuable inputs until we // are below max weight. - if (weight > max_weight) { + if (weight > max_selection_weight) { max_tx_weight_exceeded = true; // mark it in case we don't find any useful result. do { const OutputGroup& to_remove_group = heap.top(); selected_eff_value -= to_remove_group.GetSelectionAmount(); weight -= to_remove_group.m_weight; heap.pop(); - } while (!heap.empty() && weight > max_weight); + } while (!heap.empty() && weight > max_selection_weight); } // Now check if we are above the target @@ -597,11 +597,12 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx * nTargetValue, with indices corresponding to groups. If the ith * entry is true, that means the ith group in groups was selected. * param@[out] nBest Total amount of subset chosen that is closest to nTargetValue. + * paramp[in] max_selection_weight The maximum allowed weight for a selection result to be valid. * param@[in] iterations Maximum number of tries. */ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups, const CAmount& nTotalLower, const CAmount& nTargetValue, - std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000) + std::vector<char>& vfBest, CAmount& nBest, int max_selection_weight, int iterations = 1000) { std::vector<char> vfIncluded; @@ -613,6 +614,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v { vfIncluded.assign(groups.size(), false); CAmount nTotal = 0; + int selected_coins_weight{0}; bool fReachedTarget = false; for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { @@ -627,9 +629,9 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i]) { nTotal += groups[i].GetSelectionAmount(); + selected_coins_weight += groups[i].m_weight; vfIncluded[i] = true; - if (nTotal >= nTargetValue) - { + if (nTotal >= nTargetValue && selected_coins_weight <= max_selection_weight) { fReachedTarget = true; // If the total is between nTargetValue and nBest, it's our new best // approximation. @@ -639,6 +641,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v vfBest = vfIncluded; } nTotal -= groups[i].GetSelectionAmount(); + selected_coins_weight -= groups[i].m_weight; vfIncluded[i] = false; } } @@ -648,10 +651,11 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v } util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue, - CAmount change_target, FastRandomContext& rng, int max_weight) + CAmount change_target, FastRandomContext& rng, int max_selection_weight) { SelectionResult result(nTargetValue, SelectionAlgorithm::KNAPSACK); + bool max_weight_exceeded{false}; // List of values less than target std::optional<OutputGroup> lowest_larger; // Groups with selection amount smaller than the target and any change we might produce. @@ -659,9 +663,13 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c std::vector<OutputGroup> applicable_groups; CAmount nTotalLower = 0; - Shuffle(groups.begin(), groups.end(), rng); + std::shuffle(groups.begin(), groups.end(), rng); for (const OutputGroup& group : groups) { + if (group.m_weight > max_selection_weight) { + max_weight_exceeded = true; + continue; + } if (group.GetSelectionAmount() == nTargetValue) { result.AddInput(group); return result; @@ -677,11 +685,18 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c for (const auto& group : applicable_groups) { result.AddInput(group); } - return result; + if (result.GetWeight() <= max_selection_weight) return result; + else max_weight_exceeded = true; + + // Try something else + result.Clear(); } if (nTotalLower < nTargetValue) { - if (!lowest_larger) return util::Error(); + if (!lowest_larger) { + if (max_weight_exceeded) return ErrorMaxWeightExceeded(); + return util::Error(); + } result.AddInput(*lowest_larger); return result; } @@ -691,9 +706,9 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c std::vector<char> vfBest; CAmount nBest; - ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest); + ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest, max_selection_weight); if (nBest != nTargetValue && nTotalLower >= nTargetValue + change_target) { - ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest); + ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest, max_selection_weight); } // If we have a bigger coin and (either the stochastic approximation didn't find a good solution, @@ -709,7 +724,7 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c } // If the result exceeds the maximum allowed size, return closest UTXO above the target - if (result.GetWeight() > max_weight) { + if (result.GetWeight() > max_selection_weight) { // No coin above target, nothing to do. if (!lowest_larger) return ErrorMaxWeightExceeded(); @@ -728,7 +743,7 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c LogPrint(BCLog::SELECTCOINS, "%stotal %s\n", log_message, FormatMoney(nBest)); } } - + Assume(result.GetWeight() <= max_selection_weight); return result; } @@ -927,7 +942,7 @@ const std::set<std::shared_ptr<COutput>>& SelectionResult::GetInputSet() const std::vector<std::shared_ptr<COutput>> SelectionResult::GetShuffledInputVector() const { std::vector<std::shared_ptr<COutput>> coins(m_selected_inputs.begin(), m_selected_inputs.end()); - Shuffle(coins.begin(), coins.end(), FastRandomContext()); + std::shuffle(coins.begin(), coins.end(), FastRandomContext()); return coins; } diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 9fb000422c..08889c8e06 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -139,9 +139,9 @@ struct CoinSelectionParams { /** Randomness to use in the context of coin selection. */ FastRandomContext& rng_fast; /** Size of a change output in bytes, determined by the output type. */ - size_t change_output_size = 0; + int change_output_size = 0; /** Size of the input to spend a change output in virtual bytes. */ - size_t change_spend_size = 0; + int change_spend_size = 0; /** Mininmum change to target in Knapsack solver and CoinGrinder: * select coins to cover the payment and at least this value of change. */ CAmount m_min_change_target{0}; @@ -162,7 +162,7 @@ struct CoinSelectionParams { CFeeRate m_discard_feerate; /** Size of the transaction before coin selection, consisting of the header and recipient * output(s), excluding the inputs and change output(s). */ - size_t tx_noinputs_size = 0; + int tx_noinputs_size = 0; /** Indicate that we are subtracting the fee from outputs */ bool m_subtract_fee_outputs = false; /** When true, always spend all (up to OUTPUT_GROUP_MAX_ENTRIES) or none of the outputs @@ -174,10 +174,13 @@ struct CoinSelectionParams { * 1) Received from other wallets, 2) replacing other txs, 3) that have been replaced. */ bool m_include_unsafe_inputs = false; + /** The maximum weight for this transaction. */ + std::optional<int> m_max_tx_weight{std::nullopt}; - CoinSelectionParams(FastRandomContext& rng_fast, size_t change_output_size, size_t change_spend_size, + CoinSelectionParams(FastRandomContext& rng_fast, int change_output_size, int change_spend_size, CAmount min_change_target, CFeeRate effective_feerate, - CFeeRate long_term_feerate, CFeeRate discard_feerate, size_t tx_noinputs_size, bool avoid_partial) + CFeeRate long_term_feerate, CFeeRate discard_feerate, int tx_noinputs_size, bool avoid_partial, + std::optional<int> max_tx_weight = std::nullopt) : rng_fast{rng_fast}, change_output_size(change_output_size), change_spend_size(change_spend_size), @@ -186,7 +189,8 @@ struct CoinSelectionParams { m_long_term_feerate(long_term_feerate), m_discard_feerate(discard_feerate), tx_noinputs_size(tx_noinputs_size), - m_avoid_partial_spends(avoid_partial) + m_avoid_partial_spends(avoid_partial), + m_max_tx_weight(max_tx_weight) { } CoinSelectionParams(FastRandomContext& rng_fast) @@ -255,7 +259,7 @@ struct OutputGroup /** Total weight of the UTXOs in this group. */ int m_weight{0}; - OutputGroup() {} + OutputGroup() = default; OutputGroup(const CoinSelectionParams& params) : m_long_term_feerate(params.m_long_term_feerate), m_subtract_fee_outputs(params.m_subtract_fee_outputs) @@ -440,9 +444,9 @@ public: }; util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change, - int max_weight); + int max_selection_weight); -util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight); +util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_selection_weight); /** Select coins by Single Random Draw. OutputGroups are selected randomly from the eligible * outputs until the target is satisfied @@ -450,15 +454,15 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c * @param[in] utxo_pool The positive effective value OutputGroups eligible for selection * @param[in] target_value The target value to select for * @param[in] rng The randomness source to shuffle coins - * @param[in] max_weight The maximum allowed weight for a selection result to be valid + * @param[in] max_selection_weight The maximum allowed weight for a selection result to be valid * @returns If successful, a valid SelectionResult, otherwise, util::Error */ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng, - int max_weight); + int max_selection_weight); // Original coin selection algorithm as a fallback util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue, - CAmount change_target, FastRandomContext& rng, int max_weight); + CAmount change_target, FastRandomContext& rng, int max_selection_weight); } // namespace wallet #endif // BITCOIN_WALLET_COINSELECTION_H diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index a5a5f8ec6f..400b9dc44f 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -19,9 +19,9 @@ namespace wallet { bool operator<(BytePrefix a, Span<const std::byte> b) { return a.prefix < b.subspan(0, std::min(a.prefix.size(), b.size())); } bool operator<(Span<const std::byte> a, BytePrefix b) { return a.subspan(0, std::min(a.size(), b.prefix.size())) < b.prefix; } -std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) +std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& wallet_dir) { - std::vector<fs::path> paths; + std::vector<std::pair<fs::path, std::string>> paths; std::error_code ec; for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { @@ -38,21 +38,29 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) try { const fs::path path{it->path().lexically_relative(wallet_dir)}; - if (it->status().type() == fs::file_type::directory && - (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) { - // Found a directory which contains wallet.dat btree file, add it as a wallet. - paths.emplace_back(path); - } else if (it.depth() == 0 && it->symlink_status().type() == fs::file_type::regular && IsBDBFile(it->path())) { + if (it->status().type() == fs::file_type::directory) { + if (IsBDBFile(BDBDataFile(it->path()))) { + // Found a directory which contains wallet.dat btree file, add it as a wallet with BERKELEY format. + paths.emplace_back(path, "bdb"); + } else if (IsSQLiteFile(SQLiteDataFile(it->path()))) { + // Found a directory which contains wallet.dat sqlite file, add it as a wallet with SQLITE format. + paths.emplace_back(path, "sqlite"); + } + } else if (it.depth() == 0 && it->symlink_status().type() == fs::file_type::regular && it->path().extension() != ".bak") { if (it->path().filename() == "wallet.dat") { - // Found top-level wallet.dat btree file, add top level directory "" + // Found top-level wallet.dat file, add top level directory "" // as a wallet. - paths.emplace_back(); - } else { + if (IsBDBFile(it->path())) { + paths.emplace_back(fs::path(), "bdb"); + } else if (IsSQLiteFile(it->path())) { + paths.emplace_back(fs::path(), "sqlite"); + } + } else if (IsBDBFile(it->path())) { // Found top-level btree file not called wallet.dat. Current bitcoin // software will never create these files but will allow them to be // opened in a shared database environment for backwards compatibility. // Add it to the list of available wallets. - paths.emplace_back(path); + paths.emplace_back(path, "bdb"); } } } catch (const std::exception& e) { diff --git a/src/wallet/db.h b/src/wallet/db.h index b45076d10c..049af8dd19 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -30,8 +30,8 @@ bool operator<(Span<const std::byte> a, BytePrefix b); class DatabaseCursor { public: - explicit DatabaseCursor() {} - virtual ~DatabaseCursor() {} + explicit DatabaseCursor() = default; + virtual ~DatabaseCursor() = default; DatabaseCursor(const DatabaseCursor&) = delete; DatabaseCursor& operator=(const DatabaseCursor&) = delete; @@ -56,8 +56,8 @@ private: virtual bool HasKey(DataStream&& key) = 0; public: - explicit DatabaseBatch() {} - virtual ~DatabaseBatch() {} + explicit DatabaseBatch() = default; + virtual ~DatabaseBatch() = default; DatabaseBatch(const DatabaseBatch&) = delete; DatabaseBatch& operator=(const DatabaseBatch&) = delete; @@ -131,7 +131,7 @@ class WalletDatabase public: /** Create dummy DB handle */ WalletDatabase() : nUpdateCounter(0) {} - virtual ~WalletDatabase() {}; + virtual ~WalletDatabase() = default; /** Open the database if it is not already opened. */ virtual void Open() = 0; @@ -216,7 +216,7 @@ enum class DatabaseStatus { }; /** Recursively list database paths in directory. */ -std::vector<fs::path> ListDatabases(const fs::path& path); +std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& path); void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options); std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9fab1b2ee4..21e8a0b3bd 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -652,15 +652,30 @@ public: }; return out; } + bool isEncrypted(const std::string& wallet_name) override + { + auto wallets{GetWallets(m_context)}; + auto it = std::find_if(wallets.begin(), wallets.end(), [&](std::shared_ptr<CWallet> w){ return w->GetName() == wallet_name; }); + if (it != wallets.end()) return (*it)->IsCrypted(); + + // Unloaded wallet, read db + DatabaseOptions options; + options.require_existing = true; + DatabaseStatus status; + bilingual_str error; + auto db = MakeWalletDatabase(wallet_name, options, status, error); + if (!db) return false; + return WalletBatch(*db).IsEncrypted(); + } std::string getWalletDir() override { return fs::PathToString(GetWalletDir()); } - std::vector<std::string> listWalletDir() override + std::vector<std::pair<std::string, std::string>> listWalletDir() override { - std::vector<std::string> paths; - for (auto& path : ListDatabases(GetWalletDir())) { - paths.push_back(fs::PathToString(path)); + std::vector<std::pair<std::string, std::string>> paths; + for (auto& [path, format] : ListDatabases(GetWalletDir())) { + paths.emplace_back(fs::PathToString(path), format); } return paths; } diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index fe35f6b223..e26347d437 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -178,7 +178,7 @@ void UnloadWallets(WalletContext& context) wallets.pop_back(); std::vector<bilingual_str> warnings; RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings); - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); } } } // namespace wallet diff --git a/src/wallet/migrate.h b/src/wallet/migrate.h index e4826450af..58c8c0adf4 100644 --- a/src/wallet/migrate.h +++ b/src/wallet/migrate.h @@ -28,7 +28,7 @@ public: { if (open) Open(); } - ~BerkeleyRODatabase(){}; + ~BerkeleyRODatabase() = default; BerkeleyROData m_records; @@ -81,7 +81,7 @@ private: public: explicit BerkeleyROCursor(const BerkeleyRODatabase& database, Span<const std::byte> prefix = {}); - ~BerkeleyROCursor() {} + ~BerkeleyROCursor() = default; Status Next(DataStream& key, DataStream& value) override; }; @@ -102,7 +102,7 @@ private: public: explicit BerkeleyROBatch(const BerkeleyRODatabase& database) : m_database(database) {} - ~BerkeleyROBatch() {} + ~BerkeleyROBatch() = default; BerkeleyROBatch(const BerkeleyROBatch&) = delete; BerkeleyROBatch& operator=(const BerkeleyROBatch&) = delete; diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index 0c2ad06eea..838d062108 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2022 The Bitcoin Core developers +// Copyright (c) 2011-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -501,6 +501,7 @@ public: } UniValue operator()(const WitnessV1Taproot& id) const { return UniValue(UniValue::VOBJ); } + UniValue operator()(const PayToAnchor& id) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); } }; @@ -528,13 +529,13 @@ RPCHelpMan getaddressinfo() RPCResult::Type::OBJ, "", "", { {RPCResult::Type::STR, "address", "The bitcoin address validated."}, - {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address."}, + {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded output script generated by the address."}, {RPCResult::Type::BOOL, "ismine", "If the address is yours."}, {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."}, {RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."}, {RPCResult::Type::STR, "desc", /*optional=*/true, "A descriptor for spending coins sent to this address (only when solvable)."}, {RPCResult::Type::STR, "parent_desc", /*optional=*/true, "The descriptor used to derive this address if this is a descriptor wallet"}, - {RPCResult::Type::BOOL, "isscript", "If the key is a script."}, + {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script."}, {RPCResult::Type::BOOL, "ischange", "If the address was used for change output."}, {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address."}, {RPCResult::Type::NUM, "witness_version", /*optional=*/true, "The version number of the witness program."}, diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 8cddb8b099..0d0e86ed24 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -910,6 +910,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d case TxoutType::NONSTANDARD: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: + case TxoutType::ANCHOR: return "unrecognized script"; } // no default case, so the compiler can warn about missing cases NONFATAL_UNREACHABLE(); diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 2cf94a5722..f1430a3c60 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -530,19 +530,19 @@ RPCHelpMan listunspent() {RPCResult::Type::NUM, "vout", "the vout value"}, {RPCResult::Type::STR, "address", /*optional=*/true, "the bitcoin address"}, {RPCResult::Type::STR, "label", /*optional=*/true, "The associated label, or \"\" for the default label"}, - {RPCResult::Type::STR, "scriptPubKey", "the script key"}, + {RPCResult::Type::STR, "scriptPubKey", "the output script"}, {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT}, {RPCResult::Type::NUM, "confirmations", "The number of confirmations"}, {RPCResult::Type::NUM, "ancestorcount", /*optional=*/true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"}, {RPCResult::Type::NUM, "ancestorsize", /*optional=*/true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"}, {RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"}, - {RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeemScript if scriptPubKey is P2SH"}, - {RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH"}, + {RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeem script if the output script is P2SH"}, + {RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witness script if the output script is P2WSH or P2SH-P2WSH"}, {RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"}, {RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"}, {RPCResult::Type::BOOL, "reused", /*optional=*/true, "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"}, {RPCResult::Type::STR, "desc", /*optional=*/true, "(only when solvable) A descriptor for spending this output"}, - {RPCResult::Type::ARR, "parent_descs", /*optional=*/false, "List of parent descriptors for the scriptPubKey of this coin.", { + {RPCResult::Type::ARR, "parent_descs", /*optional=*/false, "List of parent descriptors for the output script of this coin.", { {RPCResult::Type::STR, "desc", "The descriptor string."}, }}, {RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions\n" diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index ac2a4826f0..601d8e4fa7 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -24,7 +24,7 @@ #include <univalue.h> using common::FeeModeFromString; -using common::FeeModes; +using common::FeeModesDetail; using common::InvalidEstimateModeErrorMessage; using common::StringForFeeReason; using common::TransactionErrorString; @@ -245,7 +245,7 @@ RPCHelpMan sendtoaddress() {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Signal that this transaction can be replaced by a transaction (BIP 125)"}, {"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\"") + "\""}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used"))}, {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n" "dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."}, {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, @@ -349,7 +349,7 @@ RPCHelpMan sendmany() {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Signal that this transaction can be replaced by a transaction (BIP 125)"}, {"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\"") + "\""}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used"))}, {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."}, }, @@ -463,7 +463,7 @@ static std::vector<RPCArg> FundTxDoc(bool solving_data = true) std::vector<RPCArg> args = { {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks", RPCArgOptions{.also_positional = true}}, {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n" - "\"" + FeeModes("\"\n\"") + "\"", RPCArgOptions{.also_positional = true}}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used")), RPCArgOptions{.also_positional = true}}, { "replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n" "Allows this transaction to be replaced by a transaction with higher fees" @@ -542,6 +542,7 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact {"minconf", UniValueType(UniValue::VNUM)}, {"maxconf", UniValueType(UniValue::VNUM)}, {"input_weights", UniValueType(UniValue::VARR)}, + {"max_tx_weight", UniValueType(UniValue::VNUM)}, }, true, true); @@ -701,6 +702,10 @@ CreatedTransactionResult FundTransaction(CWallet& wallet, const CMutableTransact } } + if (options.exists("max_tx_weight")) { + coinControl.m_max_tx_weight = options["max_tx_weight"].getInt<int>(); + } + if (recipients.empty()) throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); @@ -786,6 +791,8 @@ RPCHelpMan fundrawtransaction() }, }, }, + {"max_tx_weight", RPCArg::Type::NUM, RPCArg::Default{MAX_STANDARD_TX_WEIGHT}, "The maximum acceptable transaction weight.\n" + "Transaction building will fail if this can not be satisfied."}, }, FundTxDoc()), RPCArgOptions{ @@ -875,7 +882,7 @@ RPCHelpMan signrawtransactionwithwallet() { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, - {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"}, + {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The output script"}, {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"}, {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"}, {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"}, @@ -1011,7 +1018,7 @@ 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\"") + "\""}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used"))}, {"outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs specified as key-value pairs.\n" "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n" "At least one output of either type must be specified.\n" @@ -1198,7 +1205,7 @@ RPCHelpMan send() 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\"") + "\""}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used"))}, {"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_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", Cat<std::vector<RPCArg>>( @@ -1240,6 +1247,8 @@ RPCHelpMan send() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, + {"max_tx_weight", RPCArg::Type::NUM, RPCArg::Default{MAX_STANDARD_TX_WEIGHT}, "The maximum acceptable transaction weight.\n" + "Transaction building will fail if this can not be satisfied."}, }, FundTxDoc()), RPCArgOptions{.oneline_description="options"}}, @@ -1287,6 +1296,9 @@ RPCHelpMan send() // Automatically select coins, unless at least one is manually selected. Can // be overridden by options.add_inputs. coin_control.m_allow_other_inputs = rawTx.vin.size() == 0; + if (options.exists("max_tx_weight")) { + coin_control.m_max_tx_weight = options["max_tx_weight"].getInt<int>(); + } SetOptionsInputWeights(options["inputs"], options); // Clear tx.vout since it is not meant to be used now that we are passing outputs directly. // This sets us up for a future PR to completely remove tx from the function signature in favor of passing inputs directly @@ -1319,7 +1331,7 @@ RPCHelpMan sendall() }, {"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\"") + "\""}, + + FeeModesDetail(std::string("economical mode is used if the transaction is replaceable;\notherwise, conservative mode is used"))}, {"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_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", @@ -1697,6 +1709,8 @@ RPCHelpMan walletcreatefundedpsbt() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, + {"max_tx_weight", RPCArg::Type::NUM, RPCArg::Default{MAX_STANDARD_TX_WEIGHT}, "The maximum acceptable transaction weight.\n" + "Transaction building will fail if this can not be satisfied."}, }, FundTxDoc()), RPCArgOptions{.oneline_description="options"}}, diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 0dacfa808b..61cf36a6c1 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -431,7 +431,7 @@ static std::vector<RPCResult> TransactionDescriptionString() {RPCResult::Type::STR, "comment", /*optional=*/true, "If a comment is associated with the transaction, only present if not empty."}, {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability.\n" "May be unknown for unconfirmed transactions not in the mempool because their unconfirmed ancestors are unknown."}, - {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", { + {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", { {RPCResult::Type::STR, "desc", "The descriptor string."}, }}, }; @@ -729,7 +729,7 @@ RPCHelpMan gettransaction() {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" "'send' category of transactions."}, {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."}, - {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", { + {RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the output script of this coin.", { {RPCResult::Type::STR, "desc", "The descriptor string."}, }}, }}, diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 8c218ad766..39582b3f6a 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -68,7 +68,7 @@ static RPCHelpMan getwalletinfo() {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"}, {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"}, }, /*skip_type_check=*/true}, - {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"}, + {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"}, {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"}, {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"}, {RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."}, @@ -169,7 +169,7 @@ static RPCHelpMan listwalletdir() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue wallets(UniValue::VARR); - for (const auto& path : ListDatabases(GetWalletDir())) { + for (const auto& [path, _] : ListDatabases(GetWalletDir())) { UniValue wallet(UniValue::VOBJ); wallet.pushKV("name", path.utf8string()); wallets.push_back(std::move(wallet)); @@ -495,7 +495,7 @@ static RPCHelpMan unloadwallet() } } - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); UniValue result(UniValue::VOBJ); PushWarnings(warnings, result); diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c64aff5fe2..ae61696dd0 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -84,7 +84,7 @@ bool PermitsUncompressed(IsMineSigVersion sigversion) return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH; } -bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyScriptPubKeyMan& keystore) +bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyDataSPKM& keystore) { for (const valtype& pubkey : pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); @@ -102,7 +102,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const LegacyScriptPubKeyMan& //! scripts or simply treat any script that has been //! stored in the keystore as spendable // NOLINTNEXTLINE(misc-no-recursion) -IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true) +IsMineResult IsMineInner(const LegacyDataSPKM& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true) { IsMineResult ret = IsMineResult::NO; @@ -115,6 +115,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: + case TxoutType::ANCHOR: break; case TxoutType::PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); @@ -217,7 +218,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s } // namespace -isminetype LegacyScriptPubKeyMan::IsMine(const CScript& script) const +isminetype LegacyDataSPKM::IsMine(const CScript& script) const { switch (IsMineInner(*this, script, IsMineSigVersion::TOP)) { case IsMineResult::INVALID: @@ -231,7 +232,7 @@ isminetype LegacyScriptPubKeyMan::IsMine(const CScript& script) const assert(false); } -bool LegacyScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key) +bool LegacyDataSPKM::CheckDecryptionKey(const CKeyingMaterial& master_key) { { LOCK(cs_KeyStore); @@ -585,7 +586,7 @@ int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const return nTimeFirstKey; } -std::unique_ptr<SigningProvider> LegacyScriptPubKeyMan::GetSolvingProvider(const CScript& script) const +std::unique_ptr<SigningProvider> LegacyDataSPKM::GetSolvingProvider(const CScript& script) const { return std::make_unique<LegacySigningProvider>(*this); } @@ -721,7 +722,7 @@ void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime) NotifyFirstKeyTimeChanged(this, nTimeFirstKey); } -bool LegacyScriptPubKeyMan::LoadKey(const CKey& key, const CPubKey &pubkey) +bool LegacyDataSPKM::LoadKey(const CKey& key, const CPubKey &pubkey) { return AddKeyPubKeyInner(key, pubkey); } @@ -773,7 +774,7 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& s return true; } -bool LegacyScriptPubKeyMan::LoadCScript(const CScript& redeemScript) +bool LegacyDataSPKM::LoadCScript(const CScript& redeemScript) { /* A sanity check was added in pull #3843 to avoid adding redeemScripts * that never can be redeemed. However, old wallets may still contain @@ -788,18 +789,36 @@ bool LegacyScriptPubKeyMan::LoadCScript(const CScript& redeemScript) return FillableSigningProvider::AddCScript(redeemScript); } +void LegacyDataSPKM::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta) +{ + LOCK(cs_KeyStore); + mapKeyMetadata[keyID] = meta; +} + void LegacyScriptPubKeyMan::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta) { LOCK(cs_KeyStore); + LegacyDataSPKM::LoadKeyMetadata(keyID, meta); UpdateTimeFirstKey(meta.nCreateTime); - mapKeyMetadata[keyID] = meta; +} + +void LegacyDataSPKM::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta) +{ + LOCK(cs_KeyStore); + m_script_metadata[script_id] = meta; } void LegacyScriptPubKeyMan::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta) { LOCK(cs_KeyStore); + LegacyDataSPKM::LoadScriptMetadata(script_id, meta); UpdateTimeFirstKey(meta.nCreateTime); - m_script_metadata[script_id] = meta; +} + +bool LegacyDataSPKM::AddKeyPubKeyInner(const CKey& key, const CPubKey& pubkey) +{ + LOCK(cs_KeyStore); + return FillableSigningProvider::AddKeyPubKey(key, pubkey); } bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey) @@ -827,7 +846,7 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey& key, const CPubKey &pu return true; } -bool LegacyScriptPubKeyMan::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid) +bool LegacyDataSPKM::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid) { // Set fDecryptionThoroughlyChecked to false when the checksum is invalid if (!checksum_valid) { @@ -837,7 +856,7 @@ bool LegacyScriptPubKeyMan::LoadCryptedKey(const CPubKey &vchPubKey, const std:: return AddCryptedKeyInner(vchPubKey, vchCryptedSecret); } -bool LegacyScriptPubKeyMan::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) +bool LegacyDataSPKM::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { LOCK(cs_KeyStore); assert(mapKeys.empty()); @@ -865,13 +884,13 @@ bool LegacyScriptPubKeyMan::AddCryptedKey(const CPubKey &vchPubKey, } } -bool LegacyScriptPubKeyMan::HaveWatchOnly(const CScript &dest) const +bool LegacyDataSPKM::HaveWatchOnly(const CScript &dest) const { LOCK(cs_KeyStore); return setWatchOnly.count(dest) > 0; } -bool LegacyScriptPubKeyMan::HaveWatchOnly() const +bool LegacyDataSPKM::HaveWatchOnly() const { LOCK(cs_KeyStore); return (!setWatchOnly.empty()); @@ -905,12 +924,12 @@ bool LegacyScriptPubKeyMan::RemoveWatchOnly(const CScript &dest) return true; } -bool LegacyScriptPubKeyMan::LoadWatchOnly(const CScript &dest) +bool LegacyDataSPKM::LoadWatchOnly(const CScript &dest) { return AddWatchOnlyInMem(dest); } -bool LegacyScriptPubKeyMan::AddWatchOnlyInMem(const CScript &dest) +bool LegacyDataSPKM::AddWatchOnlyInMem(const CScript &dest) { LOCK(cs_KeyStore); setWatchOnly.insert(dest); @@ -954,7 +973,7 @@ bool LegacyScriptPubKeyMan::AddWatchOnly(const CScript& dest, int64_t nCreateTim return AddWatchOnly(dest); } -void LegacyScriptPubKeyMan::LoadHDChain(const CHDChain& chain) +void LegacyDataSPKM::LoadHDChain(const CHDChain& chain) { LOCK(cs_KeyStore); m_hd_chain = chain; @@ -975,14 +994,14 @@ void LegacyScriptPubKeyMan::AddHDChain(const CHDChain& chain) m_hd_chain = chain; } -void LegacyScriptPubKeyMan::AddInactiveHDChain(const CHDChain& chain) +void LegacyDataSPKM::AddInactiveHDChain(const CHDChain& chain) { LOCK(cs_KeyStore); assert(!chain.seed_id.IsNull()); m_inactive_hd_chains[chain.seed_id] = chain; } -bool LegacyScriptPubKeyMan::HaveKey(const CKeyID &address) const +bool LegacyDataSPKM::HaveKey(const CKeyID &address) const { LOCK(cs_KeyStore); if (!m_storage.HasEncryptionKeys()) { @@ -991,7 +1010,7 @@ bool LegacyScriptPubKeyMan::HaveKey(const CKeyID &address) const return mapCryptedKeys.count(address) > 0; } -bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey& keyOut) const +bool LegacyDataSPKM::GetKey(const CKeyID &address, CKey& keyOut) const { LOCK(cs_KeyStore); if (!m_storage.HasEncryptionKeys()) { @@ -1010,7 +1029,7 @@ bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey& keyOut) const return false; } -bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const +bool LegacyDataSPKM::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const { CKeyMetadata meta; { @@ -1030,7 +1049,7 @@ bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& inf return true; } -bool LegacyScriptPubKeyMan::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const +bool LegacyDataSPKM::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const { LOCK(cs_KeyStore); WatchKeyMap::const_iterator it = mapWatchKeys.find(address); @@ -1041,7 +1060,7 @@ bool LegacyScriptPubKeyMan::GetWatchPubKey(const CKeyID &address, CPubKey &pubke return false; } -bool LegacyScriptPubKeyMan::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const +bool LegacyDataSPKM::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const { LOCK(cs_KeyStore); if (!m_storage.HasEncryptionKeys()) { @@ -1160,7 +1179,7 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& throw std::runtime_error(std::string(__func__) + ": writing HD chain model failed"); } -void LegacyScriptPubKeyMan::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) +void LegacyDataSPKM::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) { LOCK(cs_KeyStore); if (keypool.m_pre_split) { @@ -1681,7 +1700,7 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const return set_address; } -std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPubKeys() const +std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys() const { LOCK(cs_KeyStore); std::unordered_set<CScript, SaltedSipHasher> spks; @@ -1739,7 +1758,7 @@ std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetScriptPub return spks; } -std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetNotMineScriptPubKeys() const +std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetNotMineScriptPubKeys() const { LOCK(cs_KeyStore); std::unordered_set<CScript, SaltedSipHasher> spks; @@ -1749,7 +1768,7 @@ std::unordered_set<CScript, SaltedSipHasher> LegacyScriptPubKeyMan::GetNotMineSc return spks; } -std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor() +std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor() { LOCK(cs_KeyStore); if (m_storage.IsLocked()) { @@ -1816,7 +1835,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, m_keypool_size)); + auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0); desc_spk_man->AddDescriptorKey(key, key.GetPubKey()); desc_spk_man->TopUp(); auto desc_spks = desc_spk_man->GetScriptPubKeys(); @@ -1861,7 +1880,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, m_keypool_size)); + auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0); desc_spk_man->AddDescriptorKey(master_key.key, master_key.key.GetPubKey()); desc_spk_man->TopUp(); auto desc_spks = desc_spk_man->GetScriptPubKeys(); @@ -1923,7 +1942,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, m_keypool_size)); + auto desc_spk_man = std::make_unique<DescriptorScriptPubKeyMan>(m_storage, w_desc, /*keypool_size=*/0); for (const auto& keyid : privkeyids) { CKey key; if (!GetKey(keyid, key)) { @@ -2001,7 +2020,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor() return out; } -bool LegacyScriptPubKeyMan::DeleteRecords() +bool LegacyDataSPKM::DeleteRecords() { LOCK(cs_KeyStore); WalletBatch batch(m_storage.GetDatabase()); diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 4d9f7bb1fa..6659cbf52b 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -178,7 +178,7 @@ protected: public: explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} - virtual ~ScriptPubKeyMan() {}; + virtual ~ScriptPubKeyMan() = default; virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; } virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; } @@ -278,31 +278,111 @@ static const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES { class DescriptorScriptPubKeyMan; -class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider +// Manages the data for a LegacyScriptPubKeyMan. +// This is the minimum necessary to load a legacy wallet so that it can be migrated. +class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider { -private: - //! keeps track of whether Unlock has run a thorough check before - bool fDecryptionThoroughlyChecked = true; - +protected: using WatchOnlySet = std::set<CScript>; using WatchKeyMap = std::map<CKeyID, CPubKey>; - - WalletBatch *encrypted_batch GUARDED_BY(cs_KeyStore) = nullptr; - using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>; CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore); WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore); + /* the HD chain data model (external chain counters) */ + CHDChain m_hd_chain; + std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains; + + //! keeps track of whether Unlock has run a thorough check before + bool fDecryptionThoroughlyChecked = true; + + bool AddWatchOnlyInMem(const CScript &dest); + virtual bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey); + bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); + +public: + using ScriptPubKeyMan::ScriptPubKeyMan; + + // Map from Key ID to key metadata. + std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore); + + // Map from Script ID to key metadata (for watch-only keys). + std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_KeyStore); + + // ScriptPubKeyMan overrides + bool CheckDecryptionKey(const CKeyingMaterial& master_key) override; + std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override; + std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const override; + uint256 GetID() const override { return uint256::ONE; } + // TODO: Remove IsMine when deleting LegacyScriptPubKeyMan + isminetype IsMine(const CScript& script) const override; + + // FillableSigningProvider overrides + bool HaveKey(const CKeyID &address) const override; + bool GetKey(const CKeyID &address, CKey& keyOut) const override; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; + + std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_KeyStore); + std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_KeyStore); + std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_KeyStore); + int64_t m_max_keypool_index GUARDED_BY(cs_KeyStore) = 0; + std::map<CKeyID, int64_t> m_pool_key_to_index; + + //! Load metadata (used by LoadWallet) + virtual void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata); + virtual void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata); + + //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) + bool LoadWatchOnly(const CScript &dest); + //! Returns whether the watch-only script is in the wallet + bool HaveWatchOnly(const CScript &dest) const; + //! Returns whether there are any watch-only things in the wallet + bool HaveWatchOnly() const; + //! Adds a key to the store, without saving it to disk (used by LoadWallet) + bool LoadKey(const CKey& key, const CPubKey &pubkey); + //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) + bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid); + //! Adds a CScript to the store + bool LoadCScript(const CScript& redeemScript); + //! Load a HD chain model (used by LoadWallet) + void LoadHDChain(const CHDChain& chain); + void AddInactiveHDChain(const CHDChain& chain); + const CHDChain& GetHDChain() const { return m_hd_chain; } + //! Load a keypool entry + void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool); + + //! Fetches a pubkey from mapWatchKeys if it exists there + bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const; + + /** + * Retrieves scripts that were imported by bugs into the legacy spkm and are + * simply invalid, such as a sh(sh(pkh())) script, or not watched. + */ + std::unordered_set<CScript, SaltedSipHasher> GetNotMineScriptPubKeys() const; + + /** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan. + * Does not modify this ScriptPubKeyMan. */ + std::optional<MigrationData> MigrateToDescriptor(); + /** Delete all the records ofthis LegacyScriptPubKeyMan from disk*/ + bool DeleteRecords(); +}; + +// Implements the full legacy wallet behavior +class LegacyScriptPubKeyMan : public LegacyDataSPKM +{ +private: + WalletBatch *encrypted_batch GUARDED_BY(cs_KeyStore) = nullptr; + // By default, do not scan any block until keys/scripts are generated/imported int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = UNKNOWN_TIME; //! 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); + bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey) override; /** * Private version of AddWatchOnly method which does not accept a @@ -315,7 +395,6 @@ private: */ bool AddWatchOnly(const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); - bool AddWatchOnlyInMem(const CScript &dest); //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); @@ -330,18 +409,9 @@ private: /** Add a KeyOriginInfo to the wallet */ bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info); - /* the HD chain data model (external chain counters) */ - CHDChain m_hd_chain; - std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains; - /* HD derive new child key (on internal or external chain) */ void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); - std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_KeyStore); - std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_KeyStore); - std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_KeyStore); - int64_t m_max_keypool_index GUARDED_BY(cs_KeyStore) = 0; - std::map<CKeyID, int64_t> m_pool_key_to_index; // Tracks keypool indexes to CKeyIDs of keys that have been taken out of the keypool but may be returned to it std::map<int64_t, CKeyID> m_index_to_reserved_key; @@ -378,12 +448,10 @@ private: bool TopUpChain(WalletBatch& batch, CHDChain& chain, unsigned int size); public: - LegacyScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size) : ScriptPubKeyMan(storage), m_keypool_size(keypool_size) {} + LegacyScriptPubKeyMan(WalletStorage& storage, int64_t keypool_size) : LegacyDataSPKM(storage), m_keypool_size(keypool_size) {} util::Result<CTxDestination> GetNewDestination(const OutputType type) override; - isminetype IsMine(const CScript& script) const override; - bool CheckDecryptionKey(const CKeyingMaterial& master_key) override; bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override; util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override; @@ -417,8 +485,6 @@ public: bool CanGetAddresses(bool internal = false) const override; - std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const override; - bool CanProvide(const CScript& script, SignatureData& sigdata) override; bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; @@ -427,58 +493,27 @@ public: uint256 GetID() const override; - // Map from Key ID to key metadata. - std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore); - - // Map from Script ID to key metadata (for watch-only keys). - std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_KeyStore); - //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; - //! Adds a key to the store, without saving it to disk (used by LoadWallet) - bool LoadKey(const CKey& key, const CPubKey &pubkey); //! Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); - //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid); void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); - //! Adds a CScript to the store - bool LoadCScript(const CScript& redeemScript); //! Load metadata (used by LoadWallet) - void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata); - void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata); + void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) override; + void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) override; //! Generate a new key CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); /* Set the HD chain model (chain child index counters) and writes it to the database */ void AddHDChain(const CHDChain& chain); - //! Load a HD chain model (used by LoadWallet) - void LoadHDChain(const CHDChain& chain); - const CHDChain& GetHDChain() const { return m_hd_chain; } - void AddInactiveHDChain(const CHDChain& chain); - //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) - bool LoadWatchOnly(const CScript &dest); - //! Returns whether the watch-only script is in the wallet - bool HaveWatchOnly(const CScript &dest) const; - //! Returns whether there are any watch-only things in the wallet - bool HaveWatchOnly() const; //! Remove a watch only script from the keystore bool RemoveWatchOnly(const CScript &dest); bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); - //! Fetches a pubkey from mapWatchKeys if it exists there - bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const; - /* SigningProvider overrides */ - bool HaveKey(const CKeyID &address) const override; - bool GetKey(const CKeyID &address, CKey& keyOut) const override; - bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; bool AddCScript(const CScript& redeemScript) override; - bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; - //! Load a keypool entry - void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool); bool NewKeyPool(); void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); @@ -527,28 +562,15 @@ public: const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; } std::set<CKeyID> GetKeys() const override; - std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override; - - /** - * Retrieves scripts that were imported by bugs into the legacy spkm and are - * simply invalid, such as a sh(sh(pkh())) script, or not watched. - */ - std::unordered_set<CScript, SaltedSipHasher> GetNotMineScriptPubKeys() const; - - /** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyScriptPubKeyMan. - * Does not modify this ScriptPubKeyMan. */ - std::optional<MigrationData> MigrateToDescriptor(); - /** Delete all the records ofthis LegacyScriptPubKeyMan from disk*/ - bool DeleteRecords(); }; /** Wraps a LegacyScriptPubKeyMan so that it can be returned in a new unique_ptr. Does not provide privkeys */ class LegacySigningProvider : public SigningProvider { private: - const LegacyScriptPubKeyMan& m_spk_man; + const LegacyDataSPKM& m_spk_man; public: - explicit LegacySigningProvider(const LegacyScriptPubKeyMan& spk_man) : m_spk_man(spk_man) {} + explicit LegacySigningProvider(const LegacyDataSPKM& spk_man) : m_spk_man(spk_man) {} bool GetCScript(const CScriptID &scriptid, CScript& script) const override { return m_spk_man.GetCScript(scriptid, script); } bool HaveCScript(const CScriptID &scriptid) const override { return m_spk_man.HaveCScript(scriptid); } diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 0a59353052..7abf7f59c0 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -226,7 +226,7 @@ void CoinsResult::Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher void CoinsResult::Shuffle(FastRandomContext& rng_fast) { for (auto& it : coins) { - ::Shuffle(it.second.begin(), it.second.end(), rng_fast); + std::shuffle(it.second.begin(), it.second.end(), rng_fast); } } @@ -695,26 +695,35 @@ util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, co } }; - // Maximum allowed weight - int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR); + // Maximum allowed weight for selected coins. + int max_transaction_weight = coin_selection_params.m_max_tx_weight.value_or(MAX_STANDARD_TX_WEIGHT); + int tx_weight_no_input = coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR; + int max_selection_weight = max_transaction_weight - tx_weight_no_input; + if (max_selection_weight <= 0) { + return util::Error{_("Maximum transaction weight is less than transaction weight without inputs")}; + } // SFFO frequently causes issues in the context of changeless input sets: skip BnB when SFFO is active if (!coin_selection_params.m_subtract_fee_outputs) { - if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) { + if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_selection_weight)}) { results.push_back(*bnb_result); } else append_error(std::move(bnb_result)); } - // As Knapsack and SRD can create change, also deduce change weight. - max_inputs_weight -= (coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR); + // Deduct change weight because remaining Coin Selection algorithms can create change output + int change_outputs_weight = coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR; + max_selection_weight -= change_outputs_weight; + if (max_selection_weight < 0 && results.empty()) { + return util::Error{_("Maximum transaction weight is too low, can not accommodate change output")}; + } // 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. - if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast, max_inputs_weight)}) { + if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast, max_selection_weight)}) { results.push_back(*knapsack_result); } else append_error(std::move(knapsack_result)); if (coin_selection_params.m_effective_feerate > CFeeRate{3 * coin_selection_params.m_long_term_feerate}) { // Minimize input set for feerates of at least 3×LTFRE (default: 30 ṩ/vB+) - if (auto cg_result{CoinGrinder(groups.positive_group, nTargetValue, coin_selection_params.m_min_change_target, max_inputs_weight)}) { + if (auto cg_result{CoinGrinder(groups.positive_group, nTargetValue, coin_selection_params.m_min_change_target, max_selection_weight)}) { cg_result->RecalculateWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); results.push_back(*cg_result); } else { @@ -722,7 +731,7 @@ util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, co } } - if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.m_change_fee, coin_selection_params.rng_fast, max_inputs_weight)}) { + if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.m_change_fee, coin_selection_params.rng_fast, max_selection_weight)}) { results.push_back(*srd_result); } else append_error(std::move(srd_result)); @@ -801,7 +810,7 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av coin_selection_params.m_change_fee); // Verify we haven't exceeded the maximum allowed weight - int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR); + int max_inputs_weight = coin_selection_params.m_max_tx_weight.value_or(MAX_STANDARD_TX_WEIGHT) - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR); if (op_selection_result->GetWeight() > max_inputs_weight) { return util::Error{_("The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. " "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")}; @@ -1012,7 +1021,11 @@ 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; - + coin_selection_params.m_max_tx_weight = coin_control.m_max_tx_weight.value_or(MAX_STANDARD_TX_WEIGHT); + int minimum_tx_weight = MIN_STANDARD_TX_NONWITNESS_SIZE * WITNESS_SCALE_FACTOR; + if (coin_selection_params.m_max_tx_weight.value() < minimum_tx_weight || coin_selection_params.m_max_tx_weight.value() > MAX_STANDARD_TX_WEIGHT) { + return util::Error{strprintf(_("Maximum transaction weight must be between %d and %d"), minimum_tx_weight, MAX_STANDARD_TX_WEIGHT)}; + } // Set the long term feerate estimate to the wallet's consolidate feerate coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size) @@ -1077,7 +1090,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal( if (change_spend_size == -1) { coin_selection_params.change_spend_size = DUMMY_NESTED_P2WPKH_INPUT_SIZE; } else { - coin_selection_params.change_spend_size = (size_t)change_spend_size; + coin_selection_params.change_spend_size = change_spend_size; } // Set discard feerate diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 5e3a8179a2..f2110ea3f7 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -52,7 +52,7 @@ static int TraceSqlCallback(unsigned code, void* context, void* param1, void* pa // in the log file, only expand statements that query the database, not // statements that update the database. char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr}; - LogPrintf("[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt)); + LogTrace(BCLog::WALLETDB, "[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt)); if (expanded) sqlite3_free(expanded); } return SQLITE_OK; diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 0a3243fe19..6b84f34366 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -26,7 +26,7 @@ public: std::vector<std::byte> m_prefix_range_start; std::vector<std::byte> m_prefix_range_end; - explicit SQLiteCursor() {} + explicit SQLiteCursor() = default; explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range) : m_prefix_range_start(std::move(start_range)), m_prefix_range_end(std::move(end_range)) @@ -41,7 +41,7 @@ public: class SQliteExecHandler { public: - virtual ~SQliteExecHandler() {} + virtual ~SQliteExecHandler() = default; virtual int Exec(SQLiteDatabase& database, const std::string& statement); }; diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 7bd92b471c..eb9c349c22 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1097,13 +1097,13 @@ BOOST_AUTO_TEST_CASE(effective_value_test) static util::Result<SelectionResult> CoinGrinder(const CAmount& target, const CoinSelectionParams& cs_params, const node::NodeContext& m_node, - int max_weight, + int max_selection_weight, std::function<CoinsResult(CWallet&)> coin_setup) { std::unique_ptr<CWallet> wallet = NewWallet(m_node); CoinEligibilityFilter filter(0, 0, 0); // accept all coins without ancestors Groups group = GroupOutputs(*wallet, coin_setup(*wallet), cs_params, {{filter}})[filter].all_groups; - return CoinGrinder(group.positive_group, target, cs_params.m_min_change_target, max_weight); + return CoinGrinder(group.positive_group, target, cs_params.m_min_change_target, max_selection_weight); } BOOST_AUTO_TEST_CASE(coin_grinder_tests) @@ -1135,8 +1135,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 1) Insufficient funds, select all provided coins and fail // ######################################################### CAmount target = 49.5L * COIN; - int max_weight = 10'000; // high enough to not fail for this reason. - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 10'000; // high enough to not fail for this reason. + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 10; ++j) { add_coin(available_coins, wallet, CAmount(1 * COIN)); @@ -1153,8 +1153,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 2) Test max weight exceeded // ########################### CAmount target = 29.5L * COIN; - int max_weight = 3000; - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 3000; + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 10; ++j) { add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true); @@ -1171,8 +1171,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 3) Test selection when some coins surpass the max allowed weight while others not. --> must find a good solution // ################################################################################################################ CAmount target = 25.33L * COIN; - int max_weight = 10'000; // WU - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 10'000; // WU + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 60; ++j) { // 60 UTXO --> 19,8 BTC total --> 60 × 272 WU = 16320 WU add_coin(available_coins, wallet, CAmount(0.33 * COIN), CFeeRate(5000), 144, false, 0, true); @@ -1193,8 +1193,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 4) Test that two less valuable UTXOs with a combined lower weight are preferred over a more valuable heavier UTXO // ################################################################################################################# CAmount target = 1.9L * COIN; - int max_weight = 400'000; // WU - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 400'000; // WU + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(5000), 144, false, 0, true, 148); add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 68); @@ -1215,8 +1215,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 5) Test finding a solution in a UTXO pool with mixed weights // ################################################################################################################ CAmount target = 30L * COIN; - int max_weight = 400'000; // WU - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 400'000; // WU + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 5; ++j) { // Add heavy coins {3, 6, 9, 12, 15} @@ -1244,8 +1244,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 6) Test that the lightest solution among many clones is found // ################################################################################################################# CAmount target = 9.9L * COIN; - int max_weight = 400'000; // WU - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 400'000; // WU + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; // Expected Result: 4 + 3 + 2 + 1 = 10 BTC at 400 vB add_coin(available_coins, wallet, CAmount(4 * COIN), CFeeRate(5000), 144, false, 0, true, 100); @@ -1283,8 +1283,8 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) // 7) Test that lots of tiny UTXOs can be skipped if they are too heavy while there are enough funds in lookahead // ################################################################################################################# CAmount target = 1.9L * COIN; - int max_weight = 40000; // WU - const auto& res = CoinGrinder(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 40000; // WU + const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; add_coin(available_coins, wallet, CAmount(1.8 * COIN), CFeeRate(5000), 144, false, 0, true, 2500); add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 1000); @@ -1308,13 +1308,13 @@ BOOST_AUTO_TEST_CASE(coin_grinder_tests) static util::Result<SelectionResult> SelectCoinsSRD(const CAmount& target, const CoinSelectionParams& cs_params, const node::NodeContext& m_node, - int max_weight, + int max_selection_weight, std::function<CoinsResult(CWallet&)> coin_setup) { std::unique_ptr<CWallet> wallet = NewWallet(m_node); CoinEligibilityFilter filter(0, 0, 0); // accept all coins without ancestors Groups group = GroupOutputs(*wallet, coin_setup(*wallet), cs_params, {{filter}})[filter].all_groups; - return SelectCoinsSRD(group.positive_group, target, cs_params.m_change_fee, cs_params.rng_fast, max_weight); + return SelectCoinsSRD(group.positive_group, target, cs_params.m_change_fee, cs_params.rng_fast, max_selection_weight); } BOOST_AUTO_TEST_CASE(srd_tests) @@ -1342,8 +1342,8 @@ BOOST_AUTO_TEST_CASE(srd_tests) // 1) Insufficient funds, select all provided coins and fail // ######################################################### CAmount target = 49.5L * COIN; - int max_weight = 10000; // high enough to not fail for this reason. - const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 10000; // high enough to not fail for this reason. + const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 10; ++j) { add_coin(available_coins, wallet, CAmount(1 * COIN)); @@ -1360,8 +1360,8 @@ BOOST_AUTO_TEST_CASE(srd_tests) // 2) Test max weight exceeded // ########################### CAmount target = 49.5L * COIN; - int max_weight = 3000; - const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 3000; + const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 10; ++j) { /* 10 × 1 BTC + 10 × 2 BTC = 30 BTC. 20 × 272 WU = 5440 WU */ @@ -1379,8 +1379,8 @@ BOOST_AUTO_TEST_CASE(srd_tests) // 3) Test selection when some coins surpass the max allowed weight while others not. --> must find a good solution // ################################################################################################################ CAmount target = 25.33L * COIN; - int max_weight = 10000; // WU - const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) { + int max_selection_weight = 10000; // WU + const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { CoinsResult available_coins; for (int j = 0; j < 60; ++j) { // 60 UTXO --> 19,8 BTC total --> 60 × 272 WU = 16320 WU add_coin(available_coins, wallet, CAmount(0.33 * COIN), CFeeRate(0), 144, false, 0, true); @@ -1415,7 +1415,7 @@ 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) +BOOST_AUTO_TEST_CASE(check_max_selection_weight) { const CAmount target = 49.5L * COIN; CCoinControl cc; diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp index 644a8dd7ad..209c87fd42 100644 --- a/src/wallet/test/fuzz/coinselection.cpp +++ b/src/wallet/test/fuzz/coinselection.cpp @@ -195,11 +195,11 @@ FUZZ_TARGET(coin_grinder_is_optimal) if (best_weight < std::numeric_limits<int>::max()) { // Sufficient funds and acceptable weight: CoinGrinder should find at least one solution - int high_max_weight = fuzzed_data_provider.ConsumeIntegralInRange<int>(best_weight, std::numeric_limits<int>::max()); + int high_max_selection_weight = fuzzed_data_provider.ConsumeIntegralInRange<int>(best_weight, std::numeric_limits<int>::max()); - auto result_cg = CoinGrinder(group_pos, target, coin_params.m_min_change_target, high_max_weight); + auto result_cg = CoinGrinder(group_pos, target, coin_params.m_min_change_target, high_max_selection_weight); assert(result_cg); - assert(result_cg->GetWeight() <= high_max_weight); + assert(result_cg->GetWeight() <= high_max_selection_weight); assert(result_cg->GetSelectedEffectiveValue() >= target + coin_params.m_min_change_target); assert(best_weight < result_cg->GetWeight() || (best_weight == result_cg->GetWeight() && best_amount <= result_cg->GetSelectedEffectiveValue())); if (result_cg->GetAlgoCompleted()) { @@ -210,8 +210,8 @@ FUZZ_TARGET(coin_grinder_is_optimal) } // CoinGrinder cannot ever find a better solution than the brute-forced best, or there is none in the first place - int low_max_weight = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, best_weight - 1); - auto result_cg = CoinGrinder(group_pos, target, coin_params.m_min_change_target, low_max_weight); + int low_max_selection_weight = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, best_weight - 1); + auto result_cg = CoinGrinder(group_pos, target, coin_params.m_min_change_target, low_max_selection_weight); // Max_weight should have been exceeded, or there were insufficient funds assert(!result_cg); } @@ -256,29 +256,34 @@ FUZZ_TARGET(coinselection) (void)group.EligibleForSpending(filter); } + int max_selection_weight = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()); + // Run coinselection algorithms auto result_bnb = coin_params.m_subtract_fee_outputs ? util::Error{Untranslated("BnB disabled when SFFO is enabled")} : - SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT); + SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, max_selection_weight); if (result_bnb) { assert(result_bnb->GetChange(coin_params.min_viable_change, coin_params.m_change_fee) == 0); assert(result_bnb->GetSelectedValue() >= target); + assert(result_bnb->GetWeight() <= max_selection_weight); (void)result_bnb->GetShuffledInputVector(); (void)result_bnb->GetInputSet(); } - auto result_srd = SelectCoinsSRD(group_pos, target, coin_params.m_change_fee, fast_random_context, MAX_STANDARD_TX_WEIGHT); + auto result_srd = SelectCoinsSRD(group_pos, target, coin_params.m_change_fee, fast_random_context, max_selection_weight); if (result_srd) { assert(result_srd->GetSelectedValue() >= target); assert(result_srd->GetChange(CHANGE_LOWER, coin_params.m_change_fee) > 0); // Demonstrate that SRD creates change of at least CHANGE_LOWER + assert(result_srd->GetWeight() <= max_selection_weight); result_srd->RecalculateWaste(coin_params.min_viable_change, coin_params.m_cost_of_change, coin_params.m_change_fee); (void)result_srd->GetShuffledInputVector(); (void)result_srd->GetInputSet(); } CAmount change_target{GenerateChangeTarget(target, coin_params.m_change_fee, fast_random_context)}; - auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context, MAX_STANDARD_TX_WEIGHT); + auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context, max_selection_weight); if (result_knapsack) { assert(result_knapsack->GetSelectedValue() >= target); + assert(result_knapsack->GetWeight() <= max_selection_weight); result_knapsack->RecalculateWaste(coin_params.min_viable_change, coin_params.m_cost_of_change, coin_params.m_change_fee); (void)result_knapsack->GetShuffledInputVector(); (void)result_knapsack->GetInputSet(); diff --git a/src/wallet/test/fuzz/crypter.cpp b/src/wallet/test/fuzz/crypter.cpp index 62dd1bfde0..4d6dd43c5f 100644 --- a/src/wallet/test/fuzz/crypter.cpp +++ b/src/wallet/test/fuzz/crypter.cpp @@ -27,36 +27,31 @@ FUZZ_TARGET(crypter, .init = initialize_crypter) // These values are regularly updated within `CallOneOf` std::vector<unsigned char> cipher_text_ed; CKeyingMaterial plain_text_ed; - const std::vector<unsigned char> random_key = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<unsigned char> random_key = ConsumeFixedLengthByteVector(fuzzed_data_provider, WALLET_CRYPTO_KEY_SIZE); - LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10000) + if (fuzzed_data_provider.ConsumeBool()) { + const std::string random_string = fuzzed_data_provider.ConsumeRandomLengthString(100); + SecureString secure_string(random_string.begin(), random_string.end()); + + const unsigned int derivation_method = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<unsigned int>(); + + // Limiting the value of nRounds since it is otherwise uselessly expensive and causes a timeout when fuzzing. + crypt.SetKeyFromPassphrase(/*strKeyData=*/secure_string, + /*chSalt=*/ConsumeFixedLengthByteVector(fuzzed_data_provider, WALLET_CRYPTO_SALT_SIZE), + /*nRounds=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 25000), + /*nDerivationMethod=*/derivation_method); + } + + LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 100) { CallOneOf( fuzzed_data_provider, [&] { - const std::string random_string = fuzzed_data_provider.ConsumeRandomLengthString(); - SecureString secure_string(random_string.begin(), random_string.end()); - - const unsigned int derivation_method = fuzzed_data_provider.ConsumeBool() ? 0 : fuzzed_data_provider.ConsumeIntegral<unsigned int>(); - - // Limiting the value of nRounds since it is otherwise uselessly expensive and causes a timeout when fuzzing. - crypt.SetKeyFromPassphrase(/*strKeyData=*/secure_string, - /*chSalt=*/ConsumeRandomLengthByteVector(fuzzed_data_provider), - /*nRounds=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 25000), - /*nDerivationMethod=*/derivation_method); - }, - [&] { - const std::vector<unsigned char> random_vector = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); - const CKeyingMaterial new_key(random_vector.begin(), random_vector.end()); - const std::vector<unsigned char>& new_IV = ConsumeFixedLengthByteVector(fuzzed_data_provider, 16); - crypt.SetKey(new_key, new_IV); - }, - [&] { - const std::vector<unsigned char> random_vector = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<unsigned char> random_vector = ConsumeFixedLengthByteVector(fuzzed_data_provider, WALLET_CRYPTO_KEY_SIZE); plain_text_ed = CKeyingMaterial(random_vector.begin(), random_vector.end()); }, [&] { - cipher_text_ed = ConsumeRandomLengthByteVector(fuzzed_data_provider); + cipher_text_ed = ConsumeRandomLengthByteVector(fuzzed_data_provider, 64); }, [&] { (void)crypt.Encrypt(plain_text_ed, cipher_text_ed); @@ -67,12 +62,12 @@ FUZZ_TARGET(crypter, .init = initialize_crypter) [&] { const CKeyingMaterial master_key(random_key.begin(), random_key.end()); const uint256 iv = ConsumeUInt256(fuzzed_data_provider); - EncryptSecret(master_key, plain_text_ed, iv, cipher_text_ed); + (void)EncryptSecret(master_key, plain_text_ed, iv, cipher_text_ed); }, [&] { const CKeyingMaterial master_key(random_key.begin(), random_key.end()); const uint256 iv = ConsumeUInt256(fuzzed_data_provider); - DecryptSecret(master_key, cipher_text_ed, iv, plain_text_ed); + (void)DecryptSecret(master_key, cipher_text_ed, iv, plain_text_ed); }, [&] { std::optional<CPubKey> random_pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider); @@ -82,9 +77,9 @@ FUZZ_TARGET(crypter, .init = initialize_crypter) } const CPubKey pub_key = *random_pub_key; const CKeyingMaterial master_key(random_key.begin(), random_key.end()); - const std::vector<unsigned char> crypted_secret = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<unsigned char> crypted_secret = ConsumeRandomLengthByteVector(fuzzed_data_provider, 64); CKey key; - DecryptKey(master_key, crypted_secret, pub_key, key); + (void)DecryptKey(master_key, crypted_secret, pub_key, key); }); } } diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp index 835470aeae..315efa0dca 100644 --- a/src/wallet/test/fuzz/scriptpubkeyman.cpp +++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp @@ -94,6 +94,7 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm) LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); wallet.SetLastBlockProcessed(chainstate.m_chain.Height(), chainstate.m_chain.Tip()->GetBlockHash()); + wallet.m_keypool_size = 1; } auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)}; @@ -101,23 +102,23 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm) auto spk_manager{CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)}; if (spk_manager == nullptr) return; + if (fuzzed_data_provider.ConsumeBool()) { + auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)}; + if (!wallet_desc.has_value()) { + return; + } + std::string error; + if (spk_manager->CanUpdateToWalletDescriptor(wallet_desc->first, error)) { + auto new_spk_manager{CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)}; + if (new_spk_manager != nullptr) spk_manager = new_spk_manager; + } + } + bool good_data{true}; - LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 300) { + LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 20) { CallOneOf( fuzzed_data_provider, [&] { - auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)}; - if (!wallet_desc.has_value()) { - good_data = false; - return; - } - std::string error; - if (spk_manager->CanUpdateToWalletDescriptor(wallet_desc->first, error)) { - auto new_spk_manager{CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)}; - if (new_spk_manager != nullptr) spk_manager = new_spk_manager; - } - }, - [&] { const CScript script{ConsumeScript(fuzzed_data_provider)}; auto is_mine{spk_manager->IsMine(script)}; if (is_mine == isminetype::ISMINE_SPENDABLE) { @@ -143,30 +144,12 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm) }, [&] { auto spks{spk_manager->GetScriptPubKeys()}; - for (const CScript& spk : spks) { - if (fuzzed_data_provider.ConsumeBool()) { - spk_manager->MarkUnusedAddresses(spk); - } + if (!spks.empty()) { + auto& spk{PickValue(fuzzed_data_provider, spks)}; + (void)spk_manager->MarkUnusedAddresses(spk); } }, [&] { - CKey key{ConsumePrivateKey(fuzzed_data_provider, /*compressed=*/fuzzed_data_provider.ConsumeBool())}; - if (!key.IsValid()) { - good_data = false; - return; - } - spk_manager->AddDescriptorKey(key, key.GetPubKey()); - spk_manager->TopUp(); - LOCK(spk_manager->cs_desc_man); - auto particular_key{spk_manager->GetKey(key.GetPubKey().GetID())}; - assert(*particular_key == key); - assert(spk_manager->HasPrivKey(key.GetPubKey().GetID())); - }, - [&] { - std::string descriptor; - (void)spk_manager->GetDescriptorString(descriptor, /*priv=*/fuzzed_data_provider.ConsumeBool()); - }, - [&] { LOCK(spk_manager->cs_desc_man); auto wallet_desc{spk_manager->GetWalletDescriptor()}; if (wallet_desc.descriptor->IsSingleType()) { @@ -208,6 +191,8 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm) ); } + std::string descriptor; + (void)spk_manager->GetDescriptorString(descriptor, /*priv=*/fuzzed_data_provider.ConsumeBool()); (void)spk_manager->GetEndRange(); (void)spk_manager->GetKeyPoolSize(); } diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp index b21a9a601d..ec6c9e6f3f 100644 --- a/src/wallet/test/util.cpp +++ b/src/wallet/test/util.cpp @@ -74,7 +74,7 @@ void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet) // Calls SyncWithValidationInterfaceQueue wallet->chain().waitForNotificationsIfTipChanged({}); wallet->m_chain_notifications_handler.reset(); - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); } std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database) diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h index a3e6ede81e..fc7674e961 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -61,7 +61,7 @@ public: explicit MockableCursor(const MockableData& records, bool pass) : m_cursor(records.begin()), m_cursor_end(records.end()), m_pass(pass) {} MockableCursor(const MockableData& records, bool pass, Span<const std::byte> prefix); - ~MockableCursor() {} + ~MockableCursor() = default; Status Next(DataStream& key, DataStream& value) override; }; @@ -80,7 +80,7 @@ private: public: explicit MockableBatch(MockableData& records, bool pass) : m_records(records), m_pass(pass) {} - ~MockableBatch() {} + ~MockableBatch() = default; void Flush() override {} void Close() override {} @@ -106,7 +106,7 @@ public: bool m_pass{true}; MockableDatabase(MockableData records = {}) : WalletDatabase(), m_records(records) {} - ~MockableDatabase() {}; + ~MockableDatabase() = default; void Open() override {} void AddRef() override {} diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 53f3bcc421..44ffddb168 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -889,7 +889,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletWithoutChain, BasicTestingSetup) context.args = &m_args; auto wallet = TestLoadWallet(context); BOOST_CHECK(wallet); - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); } BOOST_FIXTURE_TEST_CASE(RemoveTxs, TestChain100Setup) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d569c64b43..5584b43520 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -162,10 +162,14 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet // 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); - if (i == context.wallets.end()) return false; - context.wallets.erase(i); + { + LOCK(context.wallets_mutex); + std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet); + if (i == context.wallets.end()) return false; + context.wallets.erase(i); + } + // Notify unload so that upper layers release the shared pointer. + wallet->NotifyUnload(); // Write the wallet setting UpdateWalletSetting(chain, name, load_on_start, warnings); @@ -223,38 +227,35 @@ static std::set<std::string> g_loading_wallet_set GUARDED_BY(g_loading_wallet_mu static std::set<std::string> g_unloading_wallet_set GUARDED_BY(g_wallet_release_mutex); // Custom deleter for shared_ptr<CWallet>. -static void ReleaseWallet(CWallet* wallet) +static void FlushAndDeleteWallet(CWallet* wallet) { const std::string name = wallet->GetName(); - wallet->WalletLogPrintf("Releasing wallet\n"); + wallet->WalletLogPrintf("Releasing wallet %s..\n", name); wallet->Flush(); delete wallet; - // Wallet is now released, notify UnloadWallet, if any. + // Wallet is now released, notify WaitForDeleteWallet, if any. { LOCK(g_wallet_release_mutex); if (g_unloading_wallet_set.erase(name) == 0) { - // UnloadWallet was not called for this wallet, all done. + // WaitForDeleteWallet was not called for this wallet, all done. return; } } g_wallet_release_cv.notify_all(); } -void UnloadWallet(std::shared_ptr<CWallet>&& wallet) +void WaitForDeleteWallet(std::shared_ptr<CWallet>&& wallet) { // Mark wallet for unloading. const std::string name = wallet->GetName(); { LOCK(g_wallet_release_mutex); - auto it = g_unloading_wallet_set.insert(name); - assert(it.second); + g_unloading_wallet_set.insert(name); + // Do not expect to be the only one removing this wallet. + // Multiple threads could simultaneously be waiting for deletion. } - // The wallet can be in use so it's not possible to explicitly unload here. - // Notify the unload intent so that all remaining shared pointers are - // released. - wallet->NotifyUnload(); - // Time to ditch our shared_ptr and wait for ReleaseWallet call. + // Time to ditch our shared_ptr and wait for FlushAndDeleteWallet call. wallet.reset(); { WAIT_LOCK(g_wallet_release_mutex, lock); @@ -1037,22 +1038,22 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const if (IsAddressPreviouslySpent(dest)) { return true; } - if (IsLegacy()) { - LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan(); - assert(spk_man != nullptr); - for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) { - WitnessV0KeyHash wpkh_dest(keyid); - if (IsAddressPreviouslySpent(wpkh_dest)) { - return true; - } - ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest)); - if (IsAddressPreviouslySpent(sh_wpkh_dest)) { - return true; - } - PKHash pkh_dest(keyid); - if (IsAddressPreviouslySpent(pkh_dest)) { - return true; - } + + LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan(); + if (!spk_man) return false; + + for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) { + WitnessV0KeyHash wpkh_dest(keyid); + if (IsAddressPreviouslySpent(wpkh_dest)) { + return true; + } + ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest)); + if (IsAddressPreviouslySpent(sh_wpkh_dest)) { + return true; + } + PKHash pkh_dest(keyid); + if (IsAddressPreviouslySpent(pkh_dest)) { + return true; } } return false; @@ -1625,7 +1626,9 @@ isminetype CWallet::IsMine(const CScript& script) const } // Legacy wallet - if (IsLegacy()) return GetLegacyScriptPubKeyMan()->IsMine(script); + if (LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan()) { + return spkm->IsMine(script); + } return ISMINE_NO; } @@ -2225,8 +2228,8 @@ std::optional<PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bo // Complete if every input is now signed complete = true; - for (const auto& input : psbtx.inputs) { - complete &= PSBTInputSigned(input); + for (size_t i = 0; i < psbtx.inputs.size(); ++i) { + complete &= PSBTInputSignedAndVerified(psbtx, i, &txdata); } return {}; @@ -2309,7 +2312,7 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm) { LOCK(cs_wallet); - WalletLogPrintf("CommitTransaction:\n%s", tx->ToString()); // NOLINT(bitcoin-unterminated-logprintf) + WalletLogPrintf("CommitTransaction:\n%s\n", util::RemoveSuffixView(tx->ToString(), "\n")); // Add tx to wallet, because if it has change it's also ours, // otherwise just for transaction history. @@ -2929,7 +2932,7 @@ bool CWallet::EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestinatio return true; } -std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string) +static util::Result<fs::path> GetWalletPath(const std::string& name) { // Do some checking on wallet path. It should be either a: // @@ -2942,15 +2945,24 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory || (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) || (path_type == fs::file_type::regular && fs::PathFromString(name).filename() == fs::PathFromString(name)))) { - error_string = Untranslated(strprintf( + return util::Error{Untranslated(strprintf( "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and " "database/log.?????????? files can be stored, a location where such a directory could be created, " "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)", - name, fs::quoted(fs::PathToString(GetWalletDir())))); + name, fs::quoted(fs::PathToString(GetWalletDir()))))}; + } + return wallet_path; +} + +std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string) +{ + const auto& wallet_path = GetWalletPath(name); + if (!wallet_path) { + error_string = util::ErrorString(wallet_path); status = DatabaseStatus::FAILED_BAD_PATH; return nullptr; } - return MakeDatabase(wallet_path, options, status, error_string); + return MakeDatabase(*wallet_path, options, status, error_string); } std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) @@ -2962,7 +2974,7 @@ 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. - std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), ReleaseWallet); + std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, std::move(database)), FlushAndDeleteWallet); walletInstance->m_keypool_size = std::max(args.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{1}); walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", ""); @@ -3549,7 +3561,8 @@ std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script) c Assume(std::all_of(spk_mans.begin(), spk_mans.end(), [&script, &sigdata](ScriptPubKeyMan* spkm) { return spkm->CanProvide(script, sigdata); })); // Legacy wallet - if (IsLegacy() && GetLegacyScriptPubKeyMan()->CanProvide(script, sigdata)) spk_mans.insert(GetLegacyScriptPubKeyMan()); + LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan(); + if (spkm && spkm->CanProvide(script, sigdata)) spk_mans.insert(spkm); return spk_mans; } @@ -3579,7 +3592,8 @@ std::unique_ptr<SigningProvider> CWallet::GetSolvingProvider(const CScript& scri } // Legacy wallet - if (IsLegacy() && GetLegacyScriptPubKeyMan()->CanProvide(script, sigdata)) return GetLegacyScriptPubKeyMan()->GetSolvingProvider(script); + LegacyScriptPubKeyMan* spkm = GetLegacyScriptPubKeyMan(); + if (spkm && spkm->CanProvide(script, sigdata)) return spkm->GetSolvingProvider(script); return nullptr; } @@ -3608,6 +3622,16 @@ LegacyScriptPubKeyMan* CWallet::GetLegacyScriptPubKeyMan() const return dynamic_cast<LegacyScriptPubKeyMan*>(it->second); } +LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const +{ + if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { + return nullptr; + } + auto it = m_internal_spk_managers.find(OutputType::LEGACY); + if (it == m_internal_spk_managers.end()) return nullptr; + return dynamic_cast<LegacyDataSPKM*>(it->second); +} + LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan() { SetupLegacyScriptPubKeyMan(); @@ -3624,13 +3648,22 @@ void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKey MaybeUpdateBirthTime(spkm->GetTimeFirstKey()); } +LegacyDataSPKM* CWallet::GetOrCreateLegacyDataSPKM() +{ + SetupLegacyScriptPubKeyMan(); + return GetLegacyDataSPKM(); +} + void CWallet::SetupLegacyScriptPubKeyMan() { if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty() || IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { return; } - auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this, m_keypool_size)); + std::unique_ptr<ScriptPubKeyMan> spk_manager = m_database->Format() == "bdb_ro" ? + std::make_unique<LegacyDataSPKM>(*this) : + std::make_unique<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(); @@ -3817,11 +3850,7 @@ void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool intern bool CWallet::IsLegacy() const { - if (m_internal_spk_managers.count(OutputType::LEGACY) == 0) { - return false; - } - auto spk_man = dynamic_cast<LegacyScriptPubKeyMan*>(m_internal_spk_managers.at(OutputType::LEGACY)); - return spk_man != nullptr; + return !IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS); } DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const @@ -3998,7 +4027,7 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err { AssertLockHeld(cs_wallet); - LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan(); + LegacyDataSPKM* legacy_spkm = GetLegacyDataSPKM(); if (!Assume(legacy_spkm)) { // This shouldn't happen error = Untranslated(STR_INTERNAL_BUG("Error: Legacy wallet data missing")); @@ -4017,7 +4046,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error) { AssertLockHeld(cs_wallet); - LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan(); + LegacyDataSPKM* legacy_spkm = GetLegacyDataSPKM(); if (!Assume(legacy_spkm)) { // This shouldn't happen error = Untranslated(STR_INTERNAL_BUG("Error: Legacy wallet data missing")); @@ -4352,11 +4381,24 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle // If the wallet is still loaded, unload it so that nothing else tries to use it while we're changing it bool was_loaded = false; if (auto wallet = GetWallet(context, wallet_name)) { + if (wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { + return util::Error{_("Error: This wallet is already a descriptor wallet")}; + } + if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) { return util::Error{_("Unable to unload the wallet before migrating")}; } - UnloadWallet(std::move(wallet)); + WaitForDeleteWallet(std::move(wallet)); was_loaded = true; + } else { + // Check if the wallet is BDB + const auto& wallet_path = GetWalletPath(wallet_name); + if (!wallet_path) { + return util::Error{util::ErrorString(wallet_path)}; + } + if (!IsBDBFile(BDBDataFile(*wallet_path))) { + return util::Error{_("Error: This wallet is already a descriptor wallet")}; + } } // Load the wallet but only in the context of this function. @@ -4365,6 +4407,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle empty_context.args = context.args; DatabaseOptions options; options.require_existing = true; + options.require_format = DatabaseFormat::BERKELEY_RO; DatabaseStatus status; std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error); if (!database) { @@ -4379,6 +4422,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle // Helper to reload as normal for some of our exit scenarios const auto& reload_wallet = [&](std::shared_ptr<CWallet>& to_reload) { + // Reset options.require_format as wallets of any format may be reloaded. + options.require_format = std::nullopt; assert(to_reload.use_count() == 1); std::string name = to_reload->GetName(); to_reload.reset(); @@ -4487,7 +4532,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle error += _("\nUnable to cleanup failed migration"); return util::Error{error}; } - UnloadWallet(std::move(w)); + WaitForDeleteWallet(std::move(w)); } else { // Unloading for wallets in local context assert(w.use_count() == 1); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5bc888462f..3ea1cf48b2 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -83,12 +83,9 @@ struct bilingual_str; namespace wallet { struct WalletContext; -//! Explicitly unload and delete the wallet. -//! Blocks the current thread after signaling the unload intent so that all -//! wallet pointer owners release the wallet. -//! Note that, when blocking is not required, the wallet is implicitly unloaded -//! by the shared pointer deleter. -void UnloadWallet(std::shared_ptr<CWallet>&& wallet); +//! Explicitly delete the wallet. +//! Blocks the current thread until the wallet is destructed. +void WaitForDeleteWallet(std::shared_ptr<CWallet>&& wallet); bool AddWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet); bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings); @@ -963,8 +960,10 @@ public: //! Get the LegacyScriptPubKeyMan which is used for all types, internal, and external. LegacyScriptPubKeyMan* GetLegacyScriptPubKeyMan() const; LegacyScriptPubKeyMan* GetOrCreateLegacyScriptPubKeyMan(); + LegacyDataSPKM* GetLegacyDataSPKM() const; + LegacyDataSPKM* GetOrCreateLegacyDataSPKM(); - //! Make a LegacyScriptPubKeyMan and set it for all types, internal, and external. + //! Make a Legacy(Data)SPKM and set it for all types, internal, and external. void SetupLegacyScriptPubKeyMan(); bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const override; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f34fcfc3fd..18d6e1407e 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -187,6 +187,17 @@ bool WalletBatch::ReadBestBlock(CBlockLocator& locator) return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator); } +bool WalletBatch::IsEncrypted() +{ + DataStream prefix; + prefix << DBKeys::MASTER_KEY; + if (auto cursor = m_batch->GetNewPrefixCursor(prefix)) { + DataStream k, v; + if (cursor->Next(k, v) == DatabaseCursor::Status::MORE) return true; + } + return false; +} + bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext) { return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext); @@ -354,9 +365,9 @@ bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::stri strErr = "Error reading wallet database: CPrivKey corrupt"; return false; } - if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey)) + if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadKey(key, vchPubKey)) { - strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed"; + strErr = "Error reading wallet database: LegacyDataSPKM::LoadKey failed"; return false; } } catch (const std::exception& e) { @@ -393,9 +404,9 @@ bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, st } } - if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid)) + if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid)) { - strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed"; + strErr = "Error reading wallet database: LegacyDataSPKM::LoadCryptedKey failed"; return false; } } catch (const std::exception& e) { @@ -440,7 +451,7 @@ bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr) try { CHDChain chain; ssValue >> chain; - pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain); + pwallet->GetOrCreateLegacyDataSPKM()->LoadHDChain(chain); } catch (const std::exception& e) { if (strErr.empty()) { strErr = e.what(); @@ -584,9 +595,9 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, key >> hash; CScript script; value >> script; - if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script)) + if (!pwallet->GetOrCreateLegacyDataSPKM()->LoadCScript(script)) { - strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed"; + strErr = "Error reading wallet database: LegacyDataSPKM::LoadCScript failed"; return DBErrors::NONCRITICAL_ERROR; } return DBErrors::LOAD_OK; @@ -607,7 +618,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, key >> vchPubKey; CKeyMetadata keyMeta; value >> keyMeta; - pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta); + pwallet->GetOrCreateLegacyDataSPKM()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta); // Extract some CHDChain info from this metadata if it has any if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && !keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) { @@ -674,7 +685,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, // Set inactive chains if (!hd_chains.empty()) { - LegacyScriptPubKeyMan* legacy_spkm = pwallet->GetLegacyScriptPubKeyMan(); + LegacyDataSPKM* legacy_spkm = pwallet->GetLegacyDataSPKM(); if (legacy_spkm) { for (const auto& [hd_seed_id, chain] : hd_chains) { if (hd_seed_id != legacy_spkm->GetHDChain().seed_id) { @@ -695,7 +706,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, uint8_t fYes; value >> fYes; if (fYes == '1') { - pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script); + pwallet->GetOrCreateLegacyDataSPKM()->LoadWatchOnly(script); } return DBErrors::LOAD_OK; }); @@ -708,7 +719,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, key >> script; CKeyMetadata keyMeta; value >> keyMeta; - pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta); + pwallet->GetOrCreateLegacyDataSPKM()->LoadScriptMetadata(CScriptID(script), keyMeta); return DBErrors::LOAD_OK; }); result = std::max(result, watch_meta_res.m_result); @@ -720,7 +731,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, key >> nIndex; CKeyPool keypool; value >> keypool; - pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool); + pwallet->GetOrCreateLegacyDataSPKM()->LoadKeyPool(nIndex, keypool); return DBErrors::LOAD_OK; }); result = std::max(result, pool_res.m_result); @@ -763,7 +774,7 @@ static DBErrors LoadLegacyWalletRecords(CWallet* pwallet, DatabaseBatch& batch, // nTimeFirstKey is only reliable if all keys have metadata if (pwallet->IsLegacy() && (key_res.m_records + ckey_res.m_records + watch_script_res.m_records) != (keymeta_res.m_records + watch_meta_res.m_records)) { - auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan(); + auto spk_man = pwallet->GetLegacyScriptPubKeyMan(); if (spk_man) { LOCK(spk_man->cs_KeyStore); spk_man->UpdateTimeFirstKey(1); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 9474a59660..bffcc87202 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -247,6 +247,9 @@ public: bool WriteBestBlock(const CBlockLocator& locator); bool ReadBestBlock(CBlockLocator& locator); + // Returns true if wallet stores encryption keys + bool IsEncrypted(); + bool WriteOrderPosNext(int64_t nOrderPosNext); bool ReadPool(int64_t nPool, CKeyPool& keypool); diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index 38926c1eb8..96cb35b926 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -111,7 +111,7 @@ public: SER_READ(obj, obj.DeserializeDescriptor(descriptor_str)); } - WalletDescriptor() {} + WalletDescriptor() = default; WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index) : descriptor(descriptor), id(DescriptorID(*descriptor)), creation_time(creation_time), range_start(range_start), range_end(range_end), next_index(next_index) { } }; diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index ce8b6cfd6e..ecee2e93a9 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -22,7 +22,7 @@ public: /** Add wallets that should be opened to list of chain clients. */ virtual void Construct(node::NodeContext& node) const = 0; - virtual ~WalletInitInterface() {} + virtual ~WalletInitInterface() = default; }; extern const WalletInitInterface& g_wallet_init_interface; diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 536e471053..44cbacda64 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -24,9 +24,7 @@ #include <utility> #include <vector> -CZMQNotificationInterface::CZMQNotificationInterface() -{ -} +CZMQNotificationInterface::CZMQNotificationInterface() = default; CZMQNotificationInterface::~CZMQNotificationInterface() { diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 1108a8e354..0702ea7666 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -24,4 +24,4 @@ class CreateCache(BitcoinTestFramework): pass if __name__ == '__main__': - CreateCache().main() + CreateCache(__file__).main() diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py index 33054fd517..2e4ca83bf0 100644 --- a/test/functional/data/invalid_txs.py +++ b/test/functional/data/invalid_txs.py @@ -192,7 +192,7 @@ class SpendTooMuch(BadTxTemplate): def get_tx(self): return create_tx_with_script( - self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1)) + self.spend_tx, 0, output_script=basic_p2sh, amount=(self.spend_avail + 1)) class CreateNegative(BadTxTemplate): @@ -242,7 +242,7 @@ class TooManySigops(BadTxTemplate): lotsa_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS)) return create_tx_with_script( self.spend_tx, 0, - script_pub_key=lotsa_checksigs, + output_script=lotsa_checksigs, amount=1) def getDisabledOpcodeTemplate(opcode): diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index 3127350872..1ccc5e0ba0 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -38,7 +38,9 @@ "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwlCiXVqo3OczGiewPzzo2C+MswLWbFuk6Hou0YFcmssp6P/cGxBdmSWMrLMaOH5ErileONxnOdxCIXHqWb0m81DywEBAAA=", "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwk5iXVqo3OczGiewPzzo2C+MswLWbFuk6Hou0YFcmssp6P/cGxBdmSWMrLMaOH5ErileONxnOdxCIXHqWb0m81DywAA", "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJjFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgAIyAssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20qzAAAA=", - "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJhFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4SMgLLE6xoJI3oBqpqNlnPPAPraCHQnIEUpOho/r3oZbttKswAAA" + "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgAw2k/OT32yjCyylRYx4ANxOFZZf+ljiCy1AOaBEsymMAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJhFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4SMgLLE6xoJI3oBqpqNlnPPAPraCHQnIEUpOho/r3oZbttKswAAA", + "cHNidP8BAHUCAAAAAQCBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA", + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAgD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA" ], "invalid_with_msg": [ [ diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 7f7aa065ad..39cea2962f 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -225,4 +225,4 @@ class ExampleTest(BitcoinTestFramework): if __name__ == '__main__': - ExampleTest().main() + ExampleTest(__file__).main() diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py index 01ba2834c4..a5c8aa163a 100755 --- a/test/functional/feature_abortnode.py +++ b/test/functional/feature_abortnode.py @@ -42,4 +42,4 @@ class AbortNodeTest(BitcoinTestFramework): if __name__ == '__main__': - AbortNodeTest().main() + AbortNodeTest(__file__).main() diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py index 2efad70900..c4e60fba12 100755 --- a/test/functional/feature_addrman.py +++ b/test/functional/feature_addrman.py @@ -160,4 +160,4 @@ class AddrmanTest(BitcoinTestFramework): if __name__ == "__main__": - AddrmanTest().main() + AddrmanTest(__file__).main() diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py index 5d68f50f58..5ca46c1366 100755 --- a/test/functional/feature_anchors.py +++ b/test/functional/feature_anchors.py @@ -141,4 +141,4 @@ class AnchorsTest(BitcoinTestFramework): if __name__ == "__main__": - AnchorsTest().main() + AnchorsTest(__file__).main() diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py index e469deef49..53e94bf4df 100755 --- a/test/functional/feature_asmap.py +++ b/test/functional/feature_asmap.py @@ -30,7 +30,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal DEFAULT_ASMAP_FILENAME = 'ip_asn.map' # defined in src/init.cpp -ASMAP = '../../src/test/data/asmap.raw' # path to unit test skeleton asmap +ASMAP = 'src/test/data/asmap.raw' # path to unit test skeleton asmap VERSION = 'fec61fa21a9f46f3b17bdcd660d7f4cd90b966aad3aec593c99b35f0aca15853' def expected_messages(filename): @@ -133,7 +133,8 @@ class AsmapTest(BitcoinTestFramework): self.node = self.nodes[0] self.datadir = self.node.chain_path self.default_asmap = os.path.join(self.datadir, DEFAULT_ASMAP_FILENAME) - self.asmap_raw = os.path.join(os.path.dirname(os.path.realpath(__file__)), ASMAP) + base_dir = self.config["environment"]["SRCDIR"] + self.asmap_raw = os.path.join(base_dir, ASMAP) self.test_without_asmap_arg() self.test_asmap_with_absolute_path() @@ -146,4 +147,4 @@ class AsmapTest(BitcoinTestFramework): if __name__ == '__main__': - AsmapTest().main() + AsmapTest(__file__).main() diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 9ac8d27e9c..fd6a9518e8 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -8,28 +8,14 @@ to a hash that has been compiled into bitcoind. The assumeutxo value generated and used here is committed to in `CRegTestParams::m_assumeutxo_data` in `src/kernel/chainparams.cpp`. - -## Possible test improvements - -Interesting test cases could be loading an assumeutxo snapshot file with: - -- TODO: Valid snapshot file, but referencing a snapshot block that turns out to be - invalid, or has an invalid parent -- TODO: Valid snapshot file and snapshot block, but the block is not on the - most-work chain - -Interesting starting states could be loading a snapshot when the current chain tip is: - -- TODO: An ancestor of snapshot block -- TODO: Not an ancestor of the snapshot block but has less work -- TODO: The snapshot block -- TODO: A descendant of the snapshot block -- TODO: Not an ancestor or a descendant of the snapshot block and has more work - """ from shutil import rmtree from dataclasses import dataclass +from test_framework.blocktools import ( + create_block, + create_coinbase +) from test_framework.messages import tx_from_hex from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -52,18 +38,19 @@ class AssumeutxoTest(BitcoinTestFramework): def set_test_params(self): """Use the pregenerated, deterministic chain up to height 199.""" - self.num_nodes = 3 + self.num_nodes = 4 self.rpc_timeout = 120 self.extra_args = [ [], ["-fastprune", "-prune=1", "-blockfilterindex=1", "-coinstatsindex=1"], ["-persistmempool=0","-txindex=1", "-blockfilterindex=1", "-coinstatsindex=1"], + [] ] def setup_network(self): """Start with the nodes disconnected so that one can generate a snapshot including blocks the other hasn't yet seen.""" - self.add_nodes(3) + self.add_nodes(4) self.start_nodes(extra_args=self.extra_args) def test_invalid_snapshot_scenarios(self, valid_snapshot_path): @@ -73,9 +60,8 @@ class AssumeutxoTest(BitcoinTestFramework): bad_snapshot_path = valid_snapshot_path + '.mod' node = self.nodes[1] - def expected_error(log_msg="", rpc_details=""): - with node.assert_debug_log([log_msg]): - assert_raises_rpc_error(-32603, f"Unable to load UTXO snapshot{rpc_details}", node.loadtxoutset, bad_snapshot_path) + def expected_error(msg): + assert_raises_rpc_error(-32603, f"Unable to load UTXO snapshot: Population failed: {msg}", node.loadtxoutset, bad_snapshot_path) self.log.info(" - snapshot file with invalid file magic") parsing_error_code = -22 @@ -85,7 +71,7 @@ class AssumeutxoTest(BitcoinTestFramework): assert_raises_rpc_error(parsing_error_code, "Unable to parse metadata: Invalid UTXO set snapshot magic bytes. Please check if this is indeed a snapshot file or if you are using an outdated snapshot format.", node.loadtxoutset, bad_snapshot_path) self.log.info(" - snapshot file with unsupported version") - for version in [0, 2]: + for version in [0, 1, 3]: with open(bad_snapshot_path, 'wb') as f: f.write(valid_snapshot_contents[:5] + version.to_bytes(2, "little") + valid_snapshot_contents[7:]) assert_raises_rpc_error(parsing_error_code, f"Unable to parse metadata: Version of snapshot {version} does not match any of the supported versions.", node.loadtxoutset, bad_snapshot_path) @@ -110,47 +96,44 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info(" - snapshot file referring to a block that is not in the assumeutxo parameters") prev_block_hash = self.nodes[0].getblockhash(SNAPSHOT_BASE_HEIGHT - 1) bogus_block_hash = "0" * 64 # Represents any unknown block hash - # The height is not used for anything critical currently, so we just - # confirm the manipulation in the error message - bogus_height = 1337 for bad_block_hash in [bogus_block_hash, prev_block_hash]: with open(bad_snapshot_path, 'wb') as f: - f.write(valid_snapshot_contents[:11] + bogus_height.to_bytes(4, "little") + bytes.fromhex(bad_block_hash)[::-1] + valid_snapshot_contents[47:]) + f.write(valid_snapshot_contents[:11] + bytes.fromhex(bad_block_hash)[::-1] + valid_snapshot_contents[43:]) - msg = f"Unable to load UTXO snapshot: assumeutxo block hash in snapshot metadata not recognized (hash: {bad_block_hash}, height: {bogus_height}). The following snapshot heights are available: 110, 299." + msg = f"Unable to load UTXO snapshot: assumeutxo block hash in snapshot metadata not recognized (hash: {bad_block_hash}). The following snapshot heights are available: 110, 200, 299." assert_raises_rpc_error(-32603, msg, node.loadtxoutset, bad_snapshot_path) self.log.info(" - snapshot file with wrong number of coins") - valid_num_coins = int.from_bytes(valid_snapshot_contents[47:47 + 8], "little") + valid_num_coins = int.from_bytes(valid_snapshot_contents[43:43 + 8], "little") for off in [-1, +1]: with open(bad_snapshot_path, 'wb') as f: - f.write(valid_snapshot_contents[:47]) + f.write(valid_snapshot_contents[:43]) f.write((valid_num_coins + off).to_bytes(8, "little")) - f.write(valid_snapshot_contents[47 + 8:]) - expected_error(log_msg=f"bad snapshot - coins left over after deserializing 298 coins" if off == -1 else f"bad snapshot format or truncated snapshot after deserializing 299 coins") + f.write(valid_snapshot_contents[43 + 8:]) + expected_error(msg="Bad snapshot - coins left over after deserializing 298 coins." if off == -1 else "Bad snapshot format or truncated snapshot after deserializing 299 coins.") self.log.info(" - snapshot file with alternated but parsable UTXO data results in different hash") cases = [ # (content, offset, wrong_hash, custom_message) [b"\xff" * 32, 0, "7d52155c9a9fdc4525b637ef6170568e5dad6fabd0b1fdbb9432010b8453095b", None], # wrong outpoint hash - [(2).to_bytes(1, "little"), 32, None, "[snapshot] bad snapshot data after deserializing 1 coins"], # wrong txid coins count - [b"\xfd\xff\xff", 32, None, "[snapshot] mismatch in coins count in snapshot metadata and actual snapshot data"], # txid coins count exceeds coins left + [(2).to_bytes(1, "little"), 32, None, "Bad snapshot data after deserializing 1 coins."], # wrong txid coins count + [b"\xfd\xff\xff", 32, None, "Mismatch in coins count in snapshot metadata and actual snapshot data"], # txid coins count exceeds coins left [b"\x01", 33, "9f4d897031ab8547665b4153317ae2fdbf0130c7840b66427ebc48b881cb80ad", None], # wrong outpoint index [b"\x81", 34, "3da966ba9826fb6d2604260e01607b55ba44e1a5de298606b08704bc62570ea8", None], # wrong coin code VARINT [b"\x80", 34, "091e893b3ccb4334378709578025356c8bcb0a623f37c7c4e493133c988648e5", None], # another wrong coin code - [b"\x84\x58", 34, None, "[snapshot] bad snapshot data after deserializing 0 coins"], # wrong coin case with height 364 and coinbase 0 - [b"\xCA\xD2\x8F\x5A", 39, None, "[snapshot] bad snapshot data after deserializing 0 coins - bad tx out value"], # Amount exceeds MAX_MONEY + [b"\x84\x58", 34, None, "Bad snapshot data after deserializing 0 coins"], # wrong coin case with height 364 and coinbase 0 + [b"\xCA\xD2\x8F\x5A", 39, None, "Bad snapshot data after deserializing 0 coins - bad tx out value"], # Amount exceeds MAX_MONEY ] for content, offset, wrong_hash, custom_message in cases: with open(bad_snapshot_path, "wb") as f: - # Prior to offset: Snapshot magic, snapshot version, network magic, height, hash, coins count - f.write(valid_snapshot_contents[:(5 + 2 + 4 + 4 + 32 + 8 + offset)]) + # Prior to offset: Snapshot magic, snapshot version, network magic, hash, coins count + f.write(valid_snapshot_contents[:(5 + 2 + 4 + 32 + 8 + offset)]) f.write(content) - f.write(valid_snapshot_contents[(5 + 2 + 4 + 4 + 32 + 8 + offset + len(content)):]) + f.write(valid_snapshot_contents[(5 + 2 + 4 + 32 + 8 + offset + len(content)):]) - log_msg = custom_message if custom_message is not None else f"[snapshot] bad snapshot content hash: expected a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27, got {wrong_hash}" - expected_error(log_msg=log_msg) + msg = custom_message if custom_message is not None else f"Bad snapshot content hash: expected a4bf3407ccb2cc0145c49ebba8fa91199f8a3903daf0883875941497d2493c27, got {wrong_hash}." + expected_error(msg) def test_headers_not_synced(self, valid_snapshot_path): for node in self.nodes[1:]: @@ -201,9 +184,8 @@ class AssumeutxoTest(BitcoinTestFramework): def test_snapshot_with_less_work(self, dump_output_path): self.log.info("Test bitcoind should fail when snapshot has less accumulated work than this node.") node = self.nodes[0] - assert_equal(node.getblockcount(), FINAL_HEIGHT) - with node.assert_debug_log(expected_msgs=["[snapshot] activation failed - work does not exceed active chainstate"]): - assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", node.loadtxoutset, dump_output_path) + msg = "Unable to load UTXO snapshot: Population failed: Work does not exceed active chainstate." + assert_raises_rpc_error(-32603, msg, node.loadtxoutset, dump_output_path) def test_snapshot_block_invalidated(self, dump_output_path): self.log.info("Test snapshot is not loaded when base block is invalid.") @@ -218,6 +200,53 @@ class AssumeutxoTest(BitcoinTestFramework): assert_raises_rpc_error(-32603, msg, node.loadtxoutset, dump_output_path) node.reconsiderblock(block_hash) + def test_snapshot_in_a_divergent_chain(self, dump_output_path): + n0 = self.nodes[0] + n3 = self.nodes[3] + assert_equal(n0.getblockcount(), FINAL_HEIGHT) + assert_equal(n3.getblockcount(), START_HEIGHT) + + self.log.info("Check importing a snapshot where current chain-tip is not an ancestor of the snapshot block but has less work") + # Generate a divergent chain in n3 up to 298 + self.generate(n3, nblocks=99, sync_fun=self.no_op) + assert_equal(n3.getblockcount(), SNAPSHOT_BASE_HEIGHT - 1) + + # Try importing the snapshot and assert its success + loaded = n3.loadtxoutset(dump_output_path) + assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) + normal, snapshot = n3.getchainstates()["chainstates"] + assert_equal(normal['blocks'], START_HEIGHT + 99) + assert_equal(snapshot['blocks'], SNAPSHOT_BASE_HEIGHT) + + # Now lets sync the nodes and wait for the background validation to finish + self.connect_nodes(0, 3) + self.sync_blocks(nodes=(n0, n3)) + self.wait_until(lambda: len(n3.getchainstates()['chainstates']) == 1) + + def test_snapshot_not_on_most_work_chain(self, dump_output_path): + self.log.info("Test snapshot is not loaded when the node knows the headers of another chain with more work.") + node0 = self.nodes[0] + node1 = self.nodes[1] + # Create an alternative chain of 2 new blocks, forking off the main chain at the block before the snapshot block. + # This simulates a longer chain than the main chain when submitting these two block headers to node 1 because it is only aware of + # the main chain headers up to the snapshot height. + parent_block_hash = node0.getblockhash(SNAPSHOT_BASE_HEIGHT - 1) + block_time = node0.getblock(node0.getbestblockhash())['time'] + 1 + fork_block1 = create_block(int(parent_block_hash, 16), create_coinbase(SNAPSHOT_BASE_HEIGHT), block_time) + fork_block1.solve() + fork_block2 = create_block(fork_block1.sha256, create_coinbase(SNAPSHOT_BASE_HEIGHT + 1), block_time + 1) + fork_block2.solve() + node1.submitheader(fork_block1.serialize().hex()) + node1.submitheader(fork_block2.serialize().hex()) + msg = "A forked headers-chain with more work than the chain with the snapshot base block header exists. Please proceed to sync without AssumeUtxo." + assert_raises_rpc_error(-32603, msg, node1.loadtxoutset, dump_output_path) + # Cleanup: submit two more headers of the snapshot chain to node 1, so that it is the most-work chain again and loading + # the snapshot in future subtests succeeds + main_block1 = node0.getblock(node0.getblockhash(SNAPSHOT_BASE_HEIGHT + 1), 0) + main_block2 = node0.getblock(node0.getblockhash(SNAPSHOT_BASE_HEIGHT + 2), 0) + node1.submitheader(main_block1) + node1.submitheader(main_block2) + def run_test(self): """ Bring up two (disconnected) nodes, mine some new blocks on the first, @@ -229,6 +258,7 @@ class AssumeutxoTest(BitcoinTestFramework): n0 = self.nodes[0] n1 = self.nodes[1] n2 = self.nodes[2] + n3 = self.nodes[3] self.mini_wallet = MiniWallet(n0) @@ -267,6 +297,11 @@ class AssumeutxoTest(BitcoinTestFramework): self.log.info(f"Creating a UTXO snapshot at height {SNAPSHOT_BASE_HEIGHT}") dump_output = n0.dumptxoutset('utxos.dat') + self.log.info("Test loading snapshot when the node tip is on the same block as the snapshot") + assert_equal(n0.getblockcount(), SNAPSHOT_BASE_HEIGHT) + assert_equal(n0.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT) + self.test_snapshot_with_less_work(dump_output['path']) + self.log.info("Test loading snapshot when headers are not synced") self.test_headers_not_synced(dump_output['path']) @@ -279,6 +314,7 @@ class AssumeutxoTest(BitcoinTestFramework): # block. n1.submitheader(block) n2.submitheader(block) + n3.submitheader(block) # Ensure everyone is seeing the same headers. for n in self.nodes: @@ -305,8 +341,11 @@ class AssumeutxoTest(BitcoinTestFramework): self.test_invalid_chainstate_scenarios() self.test_invalid_file_path() self.test_snapshot_block_invalidated(dump_output['path']) + self.test_snapshot_not_on_most_work_chain(dump_output['path']) self.log.info(f"Loading snapshot into second node from {dump_output['path']}") + # This node's tip is on an ancestor block of the snapshot, which should + # be the normal case loaded = n1.loadtxoutset(dump_output['path']) assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT) assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT) @@ -484,7 +523,7 @@ class AssumeutxoTest(BitcoinTestFramework): self.connect_nodes(0, 2) self.wait_until(lambda: n2.getchainstates()['chainstates'][-1]['blocks'] == FINAL_HEIGHT) - self.sync_blocks() + self.sync_blocks(nodes=(n0, n2)) self.log.info("Ensuring background validation completes") self.wait_until(lambda: len(n2.getchainstates()['chainstates']) == 1) @@ -521,6 +560,8 @@ class AssumeutxoTest(BitcoinTestFramework): self.connect_nodes(0, 2) self.wait_until(lambda: n2.getblockcount() == FINAL_HEIGHT) + self.test_snapshot_in_a_divergent_chain(dump_output['path']) + @dataclass class Block: hash: str @@ -528,4 +569,4 @@ class Block: chain_tx: int if __name__ == '__main__': - AssumeutxoTest().main() + AssumeutxoTest(__file__).main() diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 982fa79915..03a9f666b2 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -172,4 +172,4 @@ class AssumeValidTest(BitcoinTestFramework): if __name__ == '__main__': - AssumeValidTest().main() + AssumeValidTest(__file__).main() diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py index 5cd031f852..6b53de188f 100755 --- a/test/functional/feature_bind_extra.py +++ b/test/functional/feature_bind_extra.py @@ -27,7 +27,7 @@ class BindExtraTest(BitcoinTestFramework): # Avoid any -bind= on the command line. Force the framework to avoid # adding -bind=127.0.0.1. self.bind_to_localhost_only = False - self.num_nodes = 2 + self.num_nodes = 3 def skip_test_if_missing_module(self): # Due to OS-specific network stats queries, we only run on Linux. @@ -60,14 +60,21 @@ class BindExtraTest(BitcoinTestFramework): ) port += 2 + # Node2, no -bind=...=onion, thus no extra port for Tor target. + self.expected.append( + [ + [f"-bind=127.0.0.1:{port}"], + [(loopback_ipv4, port)] + ], + ) + port += 1 + self.extra_args = list(map(lambda e: e[0], self.expected)) - self.add_nodes(self.num_nodes, self.extra_args) - # Don't start the nodes, as some of them would collide trying to bind on the same port. + self.setup_nodes() def run_test(self): - for i in range(len(self.expected)): - self.log.info(f"Starting node {i} with {self.expected[i][0]}") - self.start_node(i) + for i, (args, expected_services) in enumerate(self.expected): + self.log.info(f"Checking listening ports of node {i} with {args}") pid = self.nodes[i].process.pid binds = set(get_bind_addrs(pid)) # Remove IPv6 addresses because on some CI environments "::1" is not configured @@ -78,9 +85,7 @@ class BindExtraTest(BitcoinTestFramework): binds = set(filter(lambda e: len(e[0]) != ipv6_addr_len_bytes, binds)) # Remove RPC ports. They are not relevant for this test. binds = set(filter(lambda e: e[1] != rpc_port(i), binds)) - assert_equal(binds, set(self.expected[i][1])) - self.stop_node(i) - self.log.info(f"Stopped node {i}") + assert_equal(binds, set(expected_services)) if __name__ == '__main__': - BindExtraTest().main() + BindExtraTest(__file__).main() diff --git a/test/functional/feature_bind_port_discover.py b/test/functional/feature_bind_port_discover.py index 6e07f2f16c..568c88bcbe 100755 --- a/test/functional/feature_bind_port_discover.py +++ b/test/functional/feature_bind_port_discover.py @@ -75,4 +75,4 @@ class BindPortDiscoverTest(BitcoinTestFramework): assert found_addr1 if __name__ == '__main__': - BindPortDiscoverTest().main() + BindPortDiscoverTest(__file__).main() diff --git a/test/functional/feature_bind_port_externalip.py b/test/functional/feature_bind_port_externalip.py index 6a74ce5738..8e2ac02470 100755 --- a/test/functional/feature_bind_port_externalip.py +++ b/test/functional/feature_bind_port_externalip.py @@ -72,4 +72,4 @@ class BindPortExternalIPTest(BitcoinTestFramework): assert found if __name__ == '__main__': - BindPortExternalIPTest().main() + BindPortExternalIPTest(__file__).main() diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 14b92d6733..2d61987e94 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -412,4 +412,4 @@ class BIP68Test(BitcoinTestFramework): if __name__ == '__main__': - BIP68Test().main() + BIP68Test(__file__).main() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 932f37a083..384ca311c7 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1326,8 +1326,10 @@ class FullBlockTest(BitcoinTestFramework): block.vtx.extend(tx_list) # this is a little handier to use than the version in blocktools.py - def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])): - return create_tx_with_script(spend_tx, n, amount=value, script_pub_key=script) + def create_tx(self, spend_tx, n, value, output_script=None): + if output_script is None: + output_script = CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]) + return create_tx_with_script(spend_tx, n, amount=value, output_script=output_script) # sign a transaction, using the key we know about # this signs input 0 in tx, which is assumed to be spending output 0 in spend_tx @@ -1338,13 +1340,17 @@ class FullBlockTest(BitcoinTestFramework): return sign_input_legacy(tx, 0, spend_tx.vout[0].scriptPubKey, self.coinbase_key) - def create_and_sign_transaction(self, spend_tx, value, script=CScript([OP_TRUE])): - tx = self.create_tx(spend_tx, 0, value, script) + def create_and_sign_transaction(self, spend_tx, value, output_script=None): + if output_script is None: + output_script = CScript([OP_TRUE]) + tx = self.create_tx(spend_tx, 0, value, output_script=output_script) self.sign_tx(tx, spend_tx) tx.rehash() return tx - def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), *, version=4): + def next_block(self, number, spend=None, additional_coinbase_value=0, *, script=None, version=4): + if script is None: + script = CScript([OP_TRUE]) if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -1361,7 +1367,7 @@ class FullBlockTest(BitcoinTestFramework): else: coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees coinbase.rehash() - tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi + tx = self.create_tx(spend, 0, 1, output_script=script) # spend 1 satoshi self.sign_tx(tx, spend) tx.rehash() block = create_block(base_block_hash, coinbase, block_time, version=version, txlist=[tx]) @@ -1434,4 +1440,4 @@ class FullBlockTest(BitcoinTestFramework): if __name__ == '__main__': - FullBlockTest().main() + FullBlockTest(__file__).main() diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index 1a60c13c2c..4a43632855 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -35,4 +35,4 @@ class BlocksdirTest(BitcoinTestFramework): if __name__ == '__main__': - BlocksdirTest().main() + BlocksdirTest(__file__).main() diff --git a/test/functional/feature_blocksxor.py b/test/functional/feature_blocksxor.py new file mode 100755 index 0000000000..88e0244cd4 --- /dev/null +++ b/test/functional/feature_blocksxor.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 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 support for XORed block data and undo files (`-blocksxor` option).""" +import os + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.test_node import ErrorMatch +from test_framework.util import ( + assert_equal, + assert_greater_than, + read_xor_key, + util_xor, +) +from test_framework.wallet import MiniWallet + + +class BlocksXORTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.extra_args = [[ + '-blocksxor=1', + '-fastprune=1', # use smaller block files + '-datacarriersize=100000', # needed to pad transaction with MiniWallet + ]] + + def run_test(self): + self.log.info("Mine some blocks, to create multiple blk*.dat/rev*.dat files") + node = self.nodes[0] + wallet = MiniWallet(node) + for _ in range(5): + wallet.send_self_transfer(from_node=node, target_weight=80000) + self.generate(wallet, 1) + + block_files = list(node.blocks_path.glob('blk[0-9][0-9][0-9][0-9][0-9].dat')) + undo_files = list(node.blocks_path.glob('rev[0-9][0-9][0-9][0-9][0-9].dat')) + assert_equal(len(block_files), len(undo_files)) + assert_greater_than(len(block_files), 1) # we want at least one full block file + + self.log.info("Shut down node and un-XOR block/undo files manually") + self.stop_node(0) + xor_key = read_xor_key(node=node) + for data_file in sorted(block_files + undo_files): + self.log.debug(f"Rewriting file {data_file}...") + with open(data_file, 'rb+') as f: + xored_data = f.read() + f.seek(0) + f.write(util_xor(xored_data, xor_key, offset=0)) + + self.log.info("Check that restarting with 'blocksxor=0' fails if XOR key is present") + node.assert_start_raises_init_error(['-blocksxor=0'], + 'The blocksdir XOR-key can not be disabled when a random key was already stored!', + match=ErrorMatch.PARTIAL_REGEX) + + self.log.info("Delete XOR key, restart node with '-blocksxor=0', check blk*.dat/rev*.dat file integrity") + os.remove(node.blocks_path / 'xor.dat') + self.start_node(0, extra_args=['-blocksxor=0']) + # checklevel=2 -> verify block validity + undo data + # nblocks=0 -> verify all blocks + node.verifychain(checklevel=2, nblocks=0) + + +if __name__ == '__main__': + BlocksXORTest(__file__).main() diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index fb3f662271..dc01f8fa8f 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -195,4 +195,4 @@ class BIP65Test(BitcoinTestFramework): if __name__ == '__main__': - BIP65Test().main() + BIP65Test(__file__).main() diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py index 691163d053..b4392e6002 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -324,4 +324,4 @@ class CoinStatsIndexTest(BitcoinTestFramework): if __name__ == '__main__': - CoinStatsIndexTest().main() + CoinStatsIndexTest(__file__).main() diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 9e13a3deef..bb20e2baa8 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -371,11 +371,44 @@ class ConfArgsTest(BitcoinTestFramework): def test_acceptstalefeeestimates_arg_support(self): self.log.info("Test -acceptstalefeeestimates option support") conf_file = self.nodes[0].datadir_path / "bitcoin.conf" - for chain, chain_name in {("main", ""), ("test", "testnet3"), ("signet", "signet")}: + for chain, chain_name in {("main", ""), ("test", "testnet3"), ("signet", "signet"), ("testnet4", "testnet4")}: util.write_config(conf_file, n=0, chain=chain_name, extra_config='acceptstalefeeestimates=1\n') self.nodes[0].assert_start_raises_init_error(expected_msg=f'Error: acceptstalefeeestimates is not supported on {chain} chain.') util.write_config(conf_file, n=0, chain="regtest") # Reset to regtest + def test_testnet3_deprecation_msg(self): + self.log.info("Test testnet3 deprecation warning") + t3_warning_log = "Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4." + + def warning_msg(node, approx_size): + return f'Warning: Disk space for "{node.datadir_path / node.chain / "blocks" }" may not accommodate the block files. Approximately {approx_size} GB of data will be stored in this directory.' + + # Testnet3 node will log the warning + self.nodes[0].chain = 'testnet3' + self.nodes[0].replace_in_config([('regtest=', 'testnet='), ('[regtest]', '[test]')]) + with self.nodes[0].assert_debug_log([t3_warning_log]): + self.start_node(0) + # Some CI environments will have limited space and some others won't + # so we need to handle both cases as a valid result. + self.nodes[0].stderr.seek(0) + err = self.nodes[0].stdout.read() + self.nodes[0].stderr.seek(0) + self.nodes[0].stderr.truncate() + if err != b'' and err != warning_msg(self.nodes[0], 42): + raise AssertionError("Unexpected stderr after shutdown of Testnet3 node") + self.stop_node(0) + + # Testnet4 node will not log the warning + self.nodes[0].chain = 'testnet4' + self.nodes[0].replace_in_config([('testnet=', 'testnet4='), ('[test]', '[testnet4]')]) + with self.nodes[0].assert_debug_log([], unexpected_msgs=[t3_warning_log]): + self.start_node(0) + self.stop_node(0) + + # Reset to regtest + self.nodes[0].chain = 'regtest' + self.nodes[0].replace_in_config([('testnet4=', 'regtest='), ('[testnet4]', '[regtest]')]) + def run_test(self): self.test_log_buffer() self.test_args_log() @@ -389,6 +422,7 @@ class ConfArgsTest(BitcoinTestFramework): self.test_ignored_conf() self.test_ignored_default_conf() self.test_acceptstalefeeestimates_arg_support() + self.test_testnet3_deprecation_msg() # Remove the -datadir argument so it doesn't override the config file self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")] @@ -431,4 +465,4 @@ class ConfArgsTest(BitcoinTestFramework): if __name__ == '__main__': - ConfArgsTest().main() + ConfArgsTest(__file__).main() diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 2db9682931..df02bcc6ad 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -482,4 +482,4 @@ class BIP68_112_113Test(BitcoinTestFramework): if __name__ == '__main__': - BIP68_112_113Test().main() + BIP68_112_113Test(__file__).main() diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py index afd0246209..f1aa3961e3 100755 --- a/test/functional/feature_dbcrash.py +++ b/test/functional/feature_dbcrash.py @@ -286,4 +286,4 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): if __name__ == "__main__": - ChainstateWriteCrashTest().main() + ChainstateWriteCrashTest(__file__).main() diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 035e7151ca..48b0b745c6 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -148,4 +148,4 @@ class BIP66Test(BitcoinTestFramework): if __name__ == '__main__': - BIP66Test().main() + BIP66Test(__file__).main() diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py index 96f4aed08a..9fed99cbe5 100755 --- a/test/functional/feature_dirsymlinks.py +++ b/test/functional/feature_dirsymlinks.py @@ -38,4 +38,4 @@ class SymlinkTest(BitcoinTestFramework): if __name__ == "__main__": - SymlinkTest().main() + SymlinkTest(__file__).main() diff --git a/test/functional/feature_discover.py b/test/functional/feature_discover.py index 7f4b81114e..9eaaea3652 100755 --- a/test/functional/feature_discover.py +++ b/test/functional/feature_discover.py @@ -72,4 +72,4 @@ class DiscoverTest(BitcoinTestFramework): if __name__ == '__main__': - DiscoverTest().main() + DiscoverTest(__file__).main() diff --git a/test/functional/feature_fastprune.py b/test/functional/feature_fastprune.py index c913c4f93a..ca6877b901 100755 --- a/test/functional/feature_fastprune.py +++ b/test/functional/feature_fastprune.py @@ -26,4 +26,4 @@ class FeatureFastpruneTest(BitcoinTestFramework): if __name__ == '__main__': - FeatureFastpruneTest().main() + FeatureFastpruneTest(__file__).main() diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index ffc87f8b8b..a3dcb7afda 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -128,6 +128,14 @@ def make_tx(wallet, utxo, feerate): fee_rate=Decimal(feerate * 1000) / COIN, ) +def check_fee_estimates_btw_modes(node, expected_conservative, expected_economical): + fee_est_conservative = node.estimatesmartfee(1, estimate_mode="conservative")['feerate'] + fee_est_economical = node.estimatesmartfee(1, estimate_mode="economical")['feerate'] + fee_est_default = node.estimatesmartfee(1)['feerate'] + assert_equal(fee_est_conservative, expected_conservative) + assert_equal(fee_est_economical, expected_economical) + assert_equal(fee_est_default, expected_economical) + class EstimateFeeTest(BitcoinTestFramework): def set_test_params(self): @@ -382,6 +390,40 @@ class EstimateFeeTest(BitcoinTestFramework): self.start_node(0,extra_args=["-acceptstalefeeestimates"]) assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate) + def clear_estimates(self): + self.log.info("Restarting node with fresh estimation") + self.stop_node(0) + fee_dat = self.nodes[0].chain_path / "fee_estimates.dat" + os.remove(fee_dat) + self.start_node(0) + self.connect_nodes(0, 1) + self.connect_nodes(0, 2) + assert_equal(self.nodes[0].estimatesmartfee(1)["errors"], ["Insufficient data or no feerate found"]) + + def broadcast_and_mine(self, broadcaster, miner, feerate, count): + """Broadcast and mine some number of transactions with a specified fee rate.""" + for _ in range(count): + self.wallet.send_self_transfer(from_node=broadcaster, fee_rate=feerate) + self.sync_mempools() + self.generate(miner, 1) + + def test_estimation_modes(self): + low_feerate = Decimal("0.001") + high_feerate = Decimal("0.005") + tx_count = 24 + # Broadcast and mine high fee transactions for the first 12 blocks. + for _ in range(12): + self.broadcast_and_mine(self.nodes[1], self.nodes[2], high_feerate, tx_count) + check_fee_estimates_btw_modes(self.nodes[0], high_feerate, high_feerate) + + # We now track 12 blocks; short horizon stats will start decaying. + # Broadcast and mine low fee transactions for the next 4 blocks. + for _ in range(4): + self.broadcast_and_mine(self.nodes[1], self.nodes[2], low_feerate, tx_count) + # conservative mode will consider longer time horizons while economical mode does not + # Check the fee estimates for both modes after mining low fee transactions. + check_fee_estimates_btw_modes(self.nodes[0], high_feerate, low_feerate) + def run_test(self): self.log.info("This test is time consuming, please be patient") @@ -420,17 +462,15 @@ class EstimateFeeTest(BitcoinTestFramework): self.log.info("Test reading old fee_estimates.dat") self.test_old_fee_estimate_file() - self.log.info("Restarting node with fresh estimation") - self.stop_node(0) - fee_dat = os.path.join(self.nodes[0].chain_path, "fee_estimates.dat") - os.remove(fee_dat) - self.start_node(0) - self.connect_nodes(0, 1) - self.connect_nodes(0, 2) + self.clear_estimates() self.log.info("Testing estimates with RBF.") self.sanity_check_rbf_estimates(self.confutxo + self.memutxo) + self.clear_estimates() + self.log.info("Test estimatesmartfee modes") + self.test_estimation_modes() + self.log.info("Testing that fee estimation is disabled in blocksonly.") self.restart_node(0, ["-blocksonly"]) assert_raises_rpc_error( @@ -439,4 +479,4 @@ class EstimateFeeTest(BitcoinTestFramework): if __name__ == "__main__": - EstimateFeeTest().main() + EstimateFeeTest(__file__).main() diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index 567207915e..e71871114d 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -54,4 +54,4 @@ class FilelockTest(BitcoinTestFramework): check_wallet_filelock(True) if __name__ == '__main__': - FilelockTest().main() + FilelockTest(__file__).main() diff --git a/test/functional/feature_framework_miniwallet.py b/test/functional/feature_framework_miniwallet.py index f108289018..d1aa24e7cd 100755 --- a/test/functional/feature_framework_miniwallet.py +++ b/test/functional/feature_framework_miniwallet.py @@ -3,6 +3,9 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test MiniWallet.""" +import random +import string + from test_framework.blocktools import COINBASE_MATURITY from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -31,6 +34,20 @@ class FeatureFrameworkMiniWalletTest(BitcoinTestFramework): assert_greater_than_or_equal(tx.get_weight(), target_weight) assert_greater_than_or_equal(target_weight + 3, tx.get_weight()) + def test_wallet_tagging(self): + """Verify that tagged wallet instances are able to send funds.""" + self.log.info(f"Test tagged wallet instances...") + node = self.nodes[0] + untagged_wallet = self.wallets[0][1] + for i in range(10): + tag = ''.join(random.choice(string.ascii_letters) for _ in range(20)) + self.log.debug(f"-> ({i}) tag name: {tag}") + tagged_wallet = MiniWallet(node, tag_name=tag) + untagged_wallet.send_to(from_node=node, scriptPubKey=tagged_wallet.get_scriptPubKey(), amount=100000) + tagged_wallet.rescan_utxos() + tagged_wallet.send_self_transfer(from_node=node) + self.generate(node, 1) # clear mempool + def run_test(self): node = self.nodes[0] self.wallets = [ @@ -43,7 +60,8 @@ class FeatureFrameworkMiniWalletTest(BitcoinTestFramework): self.generate(wallet, COINBASE_MATURITY) self.test_tx_padding() + self.test_wallet_tagging() if __name__ == '__main__': - FeatureFrameworkMiniWalletTest().main() + FeatureFrameworkMiniWalletTest(__file__).main() diff --git a/test/functional/feature_help.py b/test/functional/feature_help.py index 4b66030b47..6d8a742d89 100755 --- a/test/functional/feature_help.py +++ b/test/functional/feature_help.py @@ -59,4 +59,4 @@ class HelpTest(BitcoinTestFramework): if __name__ == '__main__': - HelpTest().main() + HelpTest(__file__).main() diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py index 58ab063e71..ee484e7ec5 100755 --- a/test/functional/feature_includeconf.py +++ b/test/functional/feature_includeconf.py @@ -83,4 +83,4 @@ class IncludeConfTest(BitcoinTestFramework): assert subversion.endswith("main; relative; relative2)/") if __name__ == '__main__': - IncludeConfTest().main() + IncludeConfTest(__file__).main() diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 66c0a4f615..030bf51ed8 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -155,4 +155,4 @@ class FeatureIndexPruneTest(BitcoinTestFramework): if __name__ == '__main__': - FeatureIndexPruneTest().main() + FeatureIndexPruneTest(__file__).main() diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 22ae0c307b..659d33684e 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -149,4 +149,4 @@ class InitStressTest(BitcoinTestFramework): if __name__ == '__main__': - InitStressTest().main() + InitStressTest(__file__).main() diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py index 5129e0d328..1519c132b9 100755 --- a/test/functional/feature_loadblock.py +++ b/test/functional/feature_loadblock.py @@ -80,4 +80,4 @@ class LoadblockTest(BitcoinTestFramework): if __name__ == '__main__': - LoadblockTest().main() + LoadblockTest(__file__).main() diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index 0e9aca358d..ab817fd12d 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -101,4 +101,4 @@ class LoggingTest(BitcoinTestFramework): if __name__ == '__main__': - LoggingTest().main() + LoggingTest(__file__).main() diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py index a1774a5395..4ce9bb949c 100755 --- a/test/functional/feature_maxtipage.py +++ b/test/functional/feature_maxtipage.py @@ -62,4 +62,4 @@ class MaxTipAgeTest(BitcoinTestFramework): if __name__ == '__main__': - MaxTipAgeTest().main() + MaxTipAgeTest(__file__).main() diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 39cff7b738..136cdd024d 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -206,4 +206,4 @@ class MaxUploadTest(BitcoinTestFramework): 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() + MaxUploadTest(__file__).main() diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index 078d2ef63c..8327a0477b 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -115,4 +115,4 @@ class MinimumChainWorkTest(BitcoinTestFramework): if __name__ == '__main__': - MinimumChainWorkTest().main() + MinimumChainWorkTest(__file__).main() diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index d2b5315d31..79e8df4b5e 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -194,4 +194,4 @@ class NotificationsTest(BitcoinTestFramework): if __name__ == '__main__': - NotificationsTest().main() + NotificationsTest(__file__).main() diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index f896cb6f43..a53f78c13d 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -154,4 +154,4 @@ class NULLDUMMYTest(BitcoinTestFramework): if __name__ == '__main__': - NULLDUMMYTest().main() + NULLDUMMYTest(__file__).main() diff --git a/test/functional/feature_posix_fs_permissions.py b/test/functional/feature_posix_fs_permissions.py index 40528779e6..28b1803891 100755 --- a/test/functional/feature_posix_fs_permissions.py +++ b/test/functional/feature_posix_fs_permissions.py @@ -40,4 +40,4 @@ class PosixFsPermissionsTest(BitcoinTestFramework): if __name__ == '__main__': - PosixFsPermissionsTest().main() + PosixFsPermissionsTest(__file__).main() diff --git a/test/functional/feature_presegwit_node_upgrade.py b/test/functional/feature_presegwit_node_upgrade.py index 3d762c8197..8c1bd90083 100755 --- a/test/functional/feature_presegwit_node_upgrade.py +++ b/test/functional/feature_presegwit_node_upgrade.py @@ -54,4 +54,4 @@ class SegwitUpgradeTest(BitcoinTestFramework): if __name__ == '__main__': - SegwitUpgradeTest().main() + SegwitUpgradeTest(__file__).main() diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py index 7a6f639021..644ee5cc7f 100755 --- a/test/functional/feature_proxy.py +++ b/test/functional/feature_proxy.py @@ -148,7 +148,8 @@ class ProxyTest(BitcoinTestFramework): rv = [] addr = "15.61.23.23:1234" self.log.debug(f"Test: outgoing IPv4 connection through node {node.index} for address {addr}") - node.addnode(addr, "onetry") + # v2transport=False is used to avoid reconnections with v1 being scheduled. These could interfere with later checks. + node.addnode(addr, "onetry", v2transport=False) cmd = proxies[0].queue.get() assert isinstance(cmd, Socks5Command) # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 @@ -164,7 +165,7 @@ class ProxyTest(BitcoinTestFramework): if self.have_ipv6: addr = "[1233:3432:2434:2343:3234:2345:6546:4534]:5443" self.log.debug(f"Test: outgoing IPv6 connection through node {node.index} for address {addr}") - node.addnode(addr, "onetry") + node.addnode(addr, "onetry", v2transport=False) cmd = proxies[1].queue.get() assert isinstance(cmd, Socks5Command) # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 @@ -180,7 +181,7 @@ class ProxyTest(BitcoinTestFramework): if test_onion: addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333" self.log.debug(f"Test: outgoing onion connection through node {node.index} for address {addr}") - node.addnode(addr, "onetry") + node.addnode(addr, "onetry", v2transport=False) cmd = proxies[2].queue.get() assert isinstance(cmd, Socks5Command) assert_equal(cmd.atyp, AddressType.DOMAINNAME) @@ -195,7 +196,7 @@ class ProxyTest(BitcoinTestFramework): if test_cjdns: addr = "[fc00:1:2:3:4:5:6:7]:8888" self.log.debug(f"Test: outgoing CJDNS connection through node {node.index} for address {addr}") - node.addnode(addr, "onetry") + node.addnode(addr, "onetry", v2transport=False) cmd = proxies[1].queue.get() assert isinstance(cmd, Socks5Command) assert_equal(cmd.atyp, AddressType.DOMAINNAME) @@ -209,7 +210,7 @@ class ProxyTest(BitcoinTestFramework): addr = "node.noumenon:8333" self.log.debug(f"Test: outgoing DNS name connection through node {node.index} for address {addr}") - node.addnode(addr, "onetry") + node.addnode(addr, "onetry", v2transport=False) cmd = proxies[3].queue.get() assert isinstance(cmd, Socks5Command) assert_equal(cmd.atyp, AddressType.DOMAINNAME) @@ -457,4 +458,4 @@ class ProxyTest(BitcoinTestFramework): os.unlink(socket_path) if __name__ == '__main__': - ProxyTest().main() + ProxyTest(__file__).main() diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index 4b548ef0f3..8d924282cf 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -25,6 +25,7 @@ from test_framework.util import ( assert_equal, assert_greater_than, assert_raises_rpc_error, + try_rpc, ) # Rescans start at the earliest block up to 2 hours before a key timestamp, so @@ -479,8 +480,12 @@ class PruneTest(BitcoinTestFramework): self.log.info("Test invalid pruning command line options") self.test_invalid_command_line_options() + self.log.info("Test scanblocks can not return pruned data") self.test_scanblocks_pruned() + self.log.info("Test pruneheight reflects the presence of block and undo data") + self.test_pruneheight_undo_presence() + self.log.info("Done") def test_scanblocks_pruned(self): @@ -494,5 +499,18 @@ class PruneTest(BitcoinTestFramework): 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}) + def test_pruneheight_undo_presence(self): + node = self.nodes[2] + pruneheight = node.getblockchaininfo()["pruneheight"] + fetch_block = node.getblockhash(pruneheight - 1) + + self.connect_nodes(1, 2) + peers = node.getpeerinfo() + node.getblockfrompeer(fetch_block, peers[0]["id"]) + self.wait_until(lambda: not try_rpc(-1, "Block not available (pruned data)", node.getblock, fetch_block), timeout=5) + + new_pruneheight = node.getblockchaininfo()["pruneheight"] + assert_equal(pruneheight, new_pruneheight) + if __name__ == '__main__': - PruneTest().main() + PruneTest(__file__).main() diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 739b9b9bb9..b660b96935 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -26,15 +26,18 @@ class ReplaceByFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 + # both nodes disable full-rbf to test BIP125 signaling self.extra_args = [ [ + "-mempoolfullrbf=0", "-limitancestorcount=50", "-limitancestorsize=101", "-limitdescendantcount=200", "-limitdescendantsize=101", ], - # second node has default mempool parameters + # second node has default mempool parameters, besides mempoolfullrbf being disabled [ + "-mempoolfullrbf=0", ], ] self.supports_cli = False @@ -727,4 +730,4 @@ class ReplaceByFeeTest(BitcoinTestFramework): assert conflicting_tx['txid'] in self.nodes[0].getrawmempool() if __name__ == '__main__': - ReplaceByFeeTest().main() + ReplaceByFeeTest(__file__).main() diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index 835cd0c5cf..2961a2d356 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -12,7 +12,11 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import MAGIC_BYTES -from test_framework.util import assert_equal +from test_framework.util import ( + assert_equal, + read_xor_key, + util_xor, +) class ReindexTest(BitcoinTestFramework): @@ -39,9 +43,11 @@ class ReindexTest(BitcoinTestFramework): # 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 = self.nodes[0].blocks_path / "blk00000.dat" + xor_dat = read_xor_key(node=self.nodes[0]) + with open(blk0, 'r+b') as bf: # Read at least the first few blocks (including genesis) - b = bf.read(2000) + b = util_xor(bf.read(2000), xor_dat, offset=0) # Find the offsets of blocks 2, 3, and 4 (the first 3 blocks beyond genesis) # by searching for the regtest marker bytes (see pchMessageStart). @@ -55,12 +61,12 @@ class ReindexTest(BitcoinTestFramework): 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) + 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]) + bf.write(util_xor(b[b3_start:b4_start], xor_dat, offset=b2_start)) + bf.write(util_xor(b[b2_start:b3_start], xor_dat, offset=b3_start)) # The reindexing code should detect and accommodate out of order blocks. with self.nodes[0].assert_debug_log([ @@ -103,4 +109,4 @@ class ReindexTest(BitcoinTestFramework): if __name__ == '__main__': - ReindexTest().main() + ReindexTest(__file__).main() diff --git a/test/functional/feature_reindex_readonly.py b/test/functional/feature_reindex_readonly.py index 52c0bb26a6..858a67566f 100755 --- a/test/functional/feature_reindex_readonly.py +++ b/test/functional/feature_reindex_readonly.py @@ -87,4 +87,4 @@ class BlockstoreReindexTest(BitcoinTestFramework): if __name__ == '__main__': - BlockstoreReindexTest().main() + BlockstoreReindexTest(__file__).main() diff --git a/test/functional/feature_remove_pruned_files_on_startup.py b/test/functional/feature_remove_pruned_files_on_startup.py index 4ee653142a..2e689f2920 100755 --- a/test/functional/feature_remove_pruned_files_on_startup.py +++ b/test/functional/feature_remove_pruned_files_on_startup.py @@ -52,4 +52,4 @@ class FeatureRemovePrunedFilesOnStartupTest(BitcoinTestFramework): assert not os.path.exists(rev1) if __name__ == '__main__': - FeatureRemovePrunedFilesOnStartupTest().main() + FeatureRemovePrunedFilesOnStartupTest(__file__).main() diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 4dc19222c4..f98f326e8f 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -657,4 +657,4 @@ class SegWitTest(BitcoinTestFramework): if __name__ == '__main__': - SegWitTest().main() + SegWitTest(__file__).main() diff --git a/test/functional/feature_settings.py b/test/functional/feature_settings.py index 1cd0aeabd3..2189eac7dd 100755 --- a/test/functional/feature_settings.py +++ b/test/functional/feature_settings.py @@ -88,4 +88,4 @@ class SettingsTest(BitcoinTestFramework): if __name__ == '__main__': - SettingsTest().main() + SettingsTest(__file__).main() diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py index 291df4c518..a7277be39d 100755 --- a/test/functional/feature_shutdown.py +++ b/test/functional/feature_shutdown.py @@ -32,4 +32,4 @@ class ShutdownTest(BitcoinTestFramework): self.stop_node(0, wait=1000) if __name__ == '__main__': - ShutdownTest().main() + ShutdownTest(__file__).main() diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py index a90a2a8e5e..b648266cae 100755 --- a/test/functional/feature_signet.py +++ b/test/functional/feature_signet.py @@ -82,4 +82,4 @@ class SignetBasicTest(BitcoinTestFramework): if __name__ == '__main__': - SignetBasicTest().main() + SignetBasicTest(__file__).main() diff --git a/test/functional/feature_startupnotify.py b/test/functional/feature_startupnotify.py index a8e62c6244..1e07103725 100755 --- a/test/functional/feature_startupnotify.py +++ b/test/functional/feature_startupnotify.py @@ -39,4 +39,4 @@ class StartupNotifyTest(BitcoinTestFramework): if __name__ == '__main__': - StartupNotifyTest().main() + StartupNotifyTest(__file__).main() diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index 1a0844d240..443c1c33da 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -231,7 +231,7 @@ def default_sigmsg(ctx): codeseppos = get(ctx, "codeseppos") leaf_ver = get(ctx, "leafversion") script = get(ctx, "script_taproot") - return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex) + return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=True, leaf_script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex) else: return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=False, annex=annex) elif mode == "witv0": @@ -1766,4 +1766,4 @@ class TaprootTest(BitcoinTestFramework): if __name__ == '__main__': - TaprootTest().main() + TaprootTest(__file__).main() diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index 4720f6dea3..fc372f543d 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -37,4 +37,4 @@ class UacommentTest(BitcoinTestFramework): if __name__ == '__main__': - UacommentTest().main() + UacommentTest(__file__).main() diff --git a/test/functional/feature_unsupported_utxo_db.py b/test/functional/feature_unsupported_utxo_db.py index 6acf551216..694a8e0623 100755 --- a/test/functional/feature_unsupported_utxo_db.py +++ b/test/functional/feature_unsupported_utxo_db.py @@ -58,4 +58,4 @@ class UnsupportedUtxoDbTest(BitcoinTestFramework): if __name__ == "__main__": - UnsupportedUtxoDbTest().main() + UnsupportedUtxoDbTest(__file__).main() diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py index 0bdcc6d83d..3ab779b87d 100755 --- a/test/functional/feature_utxo_set_hash.py +++ b/test/functional/feature_utxo_set_hash.py @@ -75,4 +75,4 @@ class UTXOSetHashTest(BitcoinTestFramework): if __name__ == '__main__': - UTXOSetHashTest().main() + UTXOSetHashTest(__file__).main() diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 2c330eb681..dc25ce6c83 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -100,4 +100,4 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.wait_until(lambda: self.versionbits_in_alert_file()) if __name__ == '__main__': - VersionBitsWarningTest().main() + VersionBitsWarningTest(__file__).main() diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index a6628dcbf3..e7113f8335 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -383,4 +383,4 @@ class TestBitcoinCli(BitcoinTestFramework): if __name__ == '__main__': - TestBitcoinCli().main() + TestBitcoinCli(__file__).main() diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py index 6e32009e05..dbdceb52d1 100755 --- a/test/functional/interface_http.py +++ b/test/functional/interface_http.py @@ -106,4 +106,4 @@ class HTTPBasicsTest (BitcoinTestFramework): if __name__ == '__main__': - HTTPBasicsTest ().main () + HTTPBasicsTest(__file__).main() diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index ae8d6b226d..ba6e960476 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -201,10 +201,15 @@ class RESTTest (BitcoinTestFramework): json_obj = self.test_rest_request(f"/getutxos/checkmempool/{spending[0]}-{spending[1]}") assert_equal(len(json_obj['utxos']), 1) - # Do some invalid requests + self.log.info("Check some invalid requests") self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.JSON, body='{"checkmempool', status=400, ret_type=RetType.OBJ) self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.BIN, body='{"checkmempool', status=400, ret_type=RetType.OBJ) self.test_rest_request("/getutxos/checkmempool", http_method='POST', req_type=ReqType.JSON, status=400, ret_type=RetType.OBJ) + self.test_rest_request(f"/getutxos/{spending[0]}_+1", ret_type=RetType.OBJ, status=400) + self.test_rest_request(f"/getutxos/{spending[0]}-+1", ret_type=RetType.OBJ, status=400) + self.test_rest_request(f"/getutxos/{spending[0]}--1", ret_type=RetType.OBJ, status=400) + self.test_rest_request(f"/getutxos/{spending[0]}aa-1234", ret_type=RetType.OBJ, status=400) + self.test_rest_request(f"/getutxos/aa-1234", ret_type=RetType.OBJ, status=400) # Test limits long_uri = '/'.join([f"{txid}-{n_}" for n_ in range(20)]) @@ -436,4 +441,4 @@ class RESTTest (BitcoinTestFramework): assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid hash: {INVALID_PARAM}") if __name__ == '__main__': - RESTTest().main() + RESTTest(__file__).main() diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index 6c1855c400..9074f0a2d9 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -246,4 +246,4 @@ class RPCInterfaceTest(BitcoinTestFramework): if __name__ == '__main__': - RPCInterfaceTest().main() + RPCInterfaceTest(__file__).main() diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py index 30931a41cd..dc40986a75 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -231,4 +231,4 @@ class CoinSelectionTracepointTest(BitcoinTestFramework): if __name__ == '__main__': - CoinSelectionTracepointTest().main() + CoinSelectionTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py index 0168d9f916..a088278665 100755 --- a/test/functional/interface_usdt_mempool.py +++ b/test/functional/interface_usdt_mempool.py @@ -322,4 +322,4 @@ class MempoolTracepointTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolTracepointTest().main() + MempoolTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py index 5d7c8c2304..7b55259b63 100755 --- a/test/functional/interface_usdt_net.py +++ b/test/functional/interface_usdt_net.py @@ -168,4 +168,4 @@ class NetTracepointTest(BitcoinTestFramework): if __name__ == '__main__': - NetTracepointTest().main() + NetTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index 06cdcd10a0..ad98a3a162 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -407,4 +407,4 @@ class UTXOCacheTracepointTest(BitcoinTestFramework): if __name__ == '__main__': - UTXOCacheTracepointTest().main() + UTXOCacheTracepointTest(__file__).main() diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py index 30982393d8..9a37b96ada 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -131,4 +131,4 @@ class ValidationTracepointTest(BitcoinTestFramework): if __name__ == '__main__': - ValidationTracepointTest().main() + ValidationTracepointTest(__file__).main() diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 9f6f8919de..b960f40ccc 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -597,4 +597,4 @@ class ZMQTest (BitcoinTestFramework): if __name__ == '__main__': - ZMQTest().main() + ZMQTest(__file__).main() diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index e1cee46839..4d08575255 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -37,6 +37,7 @@ from test_framework.script_util import ( keys_to_multisig_script, MIN_PADDING, MIN_STANDARD_TX_NONWITNESS_SIZE, + PAY_TO_ANCHOR, script_to_p2sh_script, script_to_p2wsh_script, ) @@ -54,6 +55,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.num_nodes = 1 self.extra_args = [[ '-txindex','-permitbaremultisig=0', + '-mempoolfullrbf=0', ]] * self.num_nodes self.supports_cli = False @@ -389,6 +391,65 @@ class MempoolAcceptanceTest(BitcoinTestFramework): maxfeerate=0, ) + self.log.info('OP_1 <0x4e73> is able to be created and spent') + anchor_value = 10000 + create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value) + self.generate(node, 1) + + # First spend has non-empty witness, will be rejected to prevent third party wtxid malleability + anchor_nonempty_wit_spend = CTransaction() + anchor_nonempty_wit_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b"")) + anchor_nonempty_wit_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) + anchor_nonempty_wit_spend.wit.vtxinwit.append(CTxInWitness()) + anchor_nonempty_wit_spend.wit.vtxinwit[0].scriptWitness.stack.append(b"f") + anchor_nonempty_wit_spend.rehash() + + self.check_mempool_result( + result_expected=[{'txid': anchor_nonempty_wit_spend.rehash(), 'allowed': False, 'reject-reason': 'bad-witness-nonstandard'}], + rawtxs=[anchor_nonempty_wit_spend.serialize().hex()], + maxfeerate=0, + ) + + # but is consensus-legal + self.generateblock(node, self.wallet.get_address(), [anchor_nonempty_wit_spend.serialize().hex()]) + + # Without witness elements it is standard + create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value) + self.generate(node, 1) + + anchor_spend = CTransaction() + anchor_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b"")) + anchor_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) + anchor_spend.wit.vtxinwit.append(CTxInWitness()) + # It's "segwit" but txid == wtxid since there is no witness data + assert_equal(anchor_spend.rehash(), anchor_spend.getwtxid()) + + self.check_mempool_result( + result_expected=[{'txid': anchor_spend.rehash(), 'allowed': True, 'vsize': anchor_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}], + rawtxs=[anchor_spend.serialize().hex()], + maxfeerate=0, + ) + + self.log.info('But cannot be spent if nested sh()') + nested_anchor_tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx'] + nested_anchor_tx.vout[0].scriptPubKey = script_to_p2sh_script(PAY_TO_ANCHOR) + nested_anchor_tx.rehash() + self.generateblock(node, self.wallet.get_address(), [nested_anchor_tx.serialize().hex()]) + + nested_anchor_spend = CTransaction() + nested_anchor_spend.vin.append(CTxIn(COutPoint(nested_anchor_tx.sha256, 0), b"")) + nested_anchor_spend.vin[0].scriptSig = CScript([bytes(PAY_TO_ANCHOR)]) + nested_anchor_spend.vout.append(CTxOut(nested_anchor_tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE])))) + nested_anchor_spend.rehash() + + self.check_mempool_result( + result_expected=[{'txid': nested_anchor_spend.rehash(), 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Witness version reserved for soft-fork upgrades)'}], + rawtxs=[nested_anchor_spend.serialize().hex()], + maxfeerate=0, + ) + # but is consensus-legal + self.generateblock(node, self.wallet.get_address(), [nested_anchor_spend.serialize().hex()]) + self.log.info('Spending a confirmed bare multisig is okay') address = self.wallet.get_address() tx = tx_from_hex(raw_tx_reference) @@ -409,4 +470,4 @@ class MempoolAcceptanceTest(BitcoinTestFramework): ) if __name__ == '__main__': - MempoolAcceptanceTest().main() + MempoolAcceptanceTest(__file__).main() diff --git a/test/functional/mempool_accept_wtxid.py b/test/functional/mempool_accept_wtxid.py index 4767d6db22..e00e7b1ae4 100755 --- a/test/functional/mempool_accept_wtxid.py +++ b/test/functional/mempool_accept_wtxid.py @@ -125,4 +125,4 @@ class MempoolWtxidTest(BitcoinTestFramework): assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0) if __name__ == '__main__': - MempoolWtxidTest().main() + MempoolWtxidTest(__file__).main() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index a126f164aa..7c72aaae77 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -78,4 +78,4 @@ class MempoolCompatibilityTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolCompatibilityTest().main() + MempoolCompatibilityTest(__file__).main() diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py index 2e27aa988e..ed6ad8461a 100755 --- a/test/functional/mempool_datacarrier.py +++ b/test/functional/mempool_datacarrier.py @@ -88,4 +88,4 @@ class DataCarrierTest(BitcoinTestFramework): if __name__ == '__main__': - DataCarrierTest().main() + DataCarrierTest(__file__).main() diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py index e0c026207a..1ea03a8a9e 100755 --- a/test/functional/mempool_dust.py +++ b/test/functional/mempool_dust.py @@ -110,4 +110,4 @@ class DustRelayFeeTest(BitcoinTestFramework): if __name__ == '__main__': - DustRelayFeeTest().main() + DustRelayFeeTest(__file__).main() diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py index 5eebe43488..2bd88f9825 100755 --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -114,4 +114,4 @@ class MempoolExpiryTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolExpiryTest().main() + MempoolExpiryTest(__file__).main() diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 49a0a32c45..626928a49a 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -342,4 +342,4 @@ class MempoolLimitTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolLimitTest().main() + MempoolLimitTest(__file__).main() diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py index 2a64597511..6e26a684e2 100755 --- a/test/functional/mempool_package_limits.py +++ b/test/functional/mempool_package_limits.py @@ -343,4 +343,4 @@ class MempoolPackageLimitsTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolPackageLimitsTest().main() + MempoolPackageLimitsTest(__file__).main() diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py index 632425814a..fd54a8c3e1 100755 --- a/test/functional/mempool_package_onemore.py +++ b/test/functional/mempool_package_onemore.py @@ -77,4 +77,4 @@ class MempoolPackagesTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolPackagesTest().main() + MempoolPackagesTest(__file__).main() diff --git a/test/functional/mempool_package_rbf.py b/test/functional/mempool_package_rbf.py index ceb9530394..9b4269f0a0 100755 --- a/test/functional/mempool_package_rbf.py +++ b/test/functional/mempool_package_rbf.py @@ -168,11 +168,20 @@ class PackageRBFTest(BitcoinTestFramework): self.assert_mempool_contents(expected=package_txns1) self.log.info("Check replacement pays for incremental bandwidth") - package_hex3, package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE) - pkg_results3 = node.submitpackage(package_hex3) - assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {package_txns3[1].rehash()}, not enough additional fees to relay; 0.00 < 0.00000{sum([tx.get_vsize() for tx in package_txns3])}", pkg_results3["package_msg"]) - + _, placeholder_txns3 = self.create_simple_package(coin) + package_3_size = sum([tx.get_vsize() for tx in placeholder_txns3]) + incremental_sats_required = Decimal(package_3_size) / COIN + incremental_sats_short = incremental_sats_required - Decimal("0.00000001") + # Recreate the package with slightly higher fee once we know the size of the new package, but still short of required fee + failure_package_hex3, failure_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_short) + assert_equal(package_3_size, sum([tx.get_vsize() for tx in failure_package_txns3])) + pkg_results3 = node.submitpackage(failure_package_hex3) + assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {failure_package_txns3[1].rehash()}, not enough additional fees to relay; {incremental_sats_short} < {incremental_sats_required}", pkg_results3["package_msg"]) self.assert_mempool_contents(expected=package_txns1) + + success_package_hex3, success_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_required) + node.submitpackage(success_package_hex3) + self.assert_mempool_contents(expected=success_package_txns3) self.generate(node, 1) self.log.info("Check Package RBF must have strict cpfp structure") @@ -180,11 +189,14 @@ class PackageRBFTest(BitcoinTestFramework): package_hex4, package_txns4 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE) node.submitpackage(package_hex4) self.assert_mempool_contents(expected=package_txns4) - package_hex5, package_txns5 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_CHILD_FEE - Decimal("0.00000001")) + package_hex5, package_txns5 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_CHILD_FEE) pkg_results5 = node.submitpackage(package_hex5) - assert 'package RBF failed: package feerate is less than parent feerate' in pkg_results5["package_msg"] - + assert 'package RBF failed: package feerate is less than or equal to parent feerate' in pkg_results5["package_msg"] self.assert_mempool_contents(expected=package_txns4) + + package_hex5_1, package_txns5_1 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_CHILD_FEE + Decimal("0.00000001")) + node.submitpackage(package_hex5_1) + self.assert_mempool_contents(expected=package_txns5_1) self.generate(node, 1) def test_package_rbf_max_conflicts(self): @@ -584,4 +596,4 @@ class PackageRBFTest(BitcoinTestFramework): assert child_result["txid"] not in mempool_info if __name__ == "__main__": - PackageRBFTest().main() + PackageRBFTest(__file__).main() diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 4be6594de6..a844a2a1d8 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -298,4 +298,4 @@ class MempoolPackagesTest(BitcoinTestFramework): self.sync_blocks() if __name__ == '__main__': - MempoolPackagesTest().main() + MempoolPackagesTest(__file__).main() diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 32a927084a..c64c203e50 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -263,4 +263,4 @@ class MempoolPersistTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolPersistTest().main() + MempoolPersistTest(__file__).main() diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 691518ea09..74a353ab01 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -162,7 +162,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.log.info("Generate a block") last_block = self.generate(self.nodes[0], 1) # generate() implicitly syncs blocks, so that peer 1 gets the block before timelock_tx - # Otherwise, peer 1 would put the timelock_tx in m_recent_rejects + # Otherwise, peer 1 would put the timelock_tx in m_lazy_recent_rejects self.log.info("The time-locked transaction can now be spent") timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) @@ -194,4 +194,4 @@ class MempoolCoinbaseTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolCoinbaseTest().main() + MempoolCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py index c10052372d..720255b9e3 100755 --- a/test/functional/mempool_resurrect.py +++ b/test/functional/mempool_resurrect.py @@ -55,4 +55,4 @@ class MempoolCoinbaseTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolCoinbaseTest().main() + MempoolCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py index d3fb5f9119..4656176a75 100755 --- a/test/functional/mempool_sigoplimit.py +++ b/test/functional/mempool_sigoplimit.py @@ -196,4 +196,4 @@ class BytesPerSigOpTest(BitcoinTestFramework): if __name__ == '__main__': - BytesPerSigOpTest().main() + BytesPerSigOpTest(__file__).main() diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py index a7cb2ba602..64ab33d3ff 100755 --- a/test/functional/mempool_spend_coinbase.py +++ b/test/functional/mempool_spend_coinbase.py @@ -57,4 +57,4 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolSpendCoinbaseTest().main() + MempoolSpendCoinbaseTest(__file__).main() diff --git a/test/functional/mempool_truc.py b/test/functional/mempool_truc.py index e1f3d77201..28f3256ef1 100755 --- a/test/functional/mempool_truc.py +++ b/test/functional/mempool_truc.py @@ -162,7 +162,7 @@ class MempoolTRUC(BitcoinTestFramework): self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]]) - @cleanup(extra_args=None) + @cleanup(extra_args=["-mempoolfullrbf=0"]) def test_truc_bip125(self): node = self.nodes[0] self.log.info("Test TRUC transactions that don't signal BIP125 are replaceable") @@ -644,4 +644,4 @@ class MempoolTRUC(BitcoinTestFramework): if __name__ == "__main__": - MempoolTRUC().main() + MempoolTRUC(__file__).main() diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py index 12de750731..7c96b4b570 100755 --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -109,4 +109,4 @@ class MempoolUnbroadcastTest(BitcoinTestFramework): if __name__ == "__main__": - MempoolUnbroadcastTest().main() + MempoolUnbroadcastTest(__file__).main() diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py index 8350e9c91e..1754991756 100755 --- a/test/functional/mempool_updatefromblock.py +++ b/test/functional/mempool_updatefromblock.py @@ -103,4 +103,4 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework): if __name__ == '__main__': - MempoolUpdateFromBlockTest().main() + MempoolUpdateFromBlockTest(__file__).main() diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 5f2dde8eac..6a364a4815 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -325,4 +325,4 @@ class MiningTest(BitcoinTestFramework): if __name__ == '__main__': - MiningTest().main() + MiningTest(__file__).main() diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py index c0e7195c82..2d15151e65 100755 --- a/test/functional/mining_getblocktemplate_longpoll.py +++ b/test/functional/mining_getblocktemplate_longpoll.py @@ -73,4 +73,4 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): assert not thr.is_alive() if __name__ == '__main__': - GetBlockTemplateLPTest().main() + GetBlockTemplateLPTest(__file__).main() diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index c5f34e3ecb..eb55202e16 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -305,4 +305,4 @@ class PrioritiseTransactionTest(BitcoinTestFramework): assert template != new_template if __name__ == '__main__': - PrioritiseTransactionTest().main() + PrioritiseTransactionTest(__file__).main() diff --git a/test/functional/p2p_1p1c_network.py b/test/functional/p2p_1p1c_network.py index ea59248506..c3cdb3e0b3 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -163,4 +163,4 @@ class PackageRelayTest(BitcoinTestFramework): if __name__ == '__main__': - PackageRelayTest().main() + PackageRelayTest(__file__).main() diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py index bd766a279e..ee0cbdfa19 100755 --- a/test/functional/p2p_add_connections.py +++ b/test/functional/p2p_add_connections.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2021 The Bitcoin Core developers +# Copyright (c) 2020-present 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 add_outbound_p2p_connection test framework functionality""" @@ -11,6 +11,14 @@ from test_framework.util import ( check_node_connections, ) + +class VersionSender(P2PInterface): + def on_open(self): + assert self.on_connection_send_msg is not None + self.send_version() + assert self.on_connection_send_msg is None + + class P2PFeelerReceiver(P2PInterface): def on_version(self, message): # The bitcoind node closes feeler connections as soon as a version @@ -106,5 +114,19 @@ class P2PAddConnections(BitcoinTestFramework): # Feeler connections do not request tx relay assert_equal(feeler_conn.last_message["version"].relay, 0) + self.log.info("Send version message early to node") + # Normally the test framework would be shy and send the version message + # only after it received one. See the on_version method. Check that + # bitcoind behaves properly when a version is sent unexpectedly (but + # tolerably) early. + # + # This checks that bitcoind sends its own version prior to processing + # the remote version (and replying with a verack). Otherwise it would + # be violating its own rules, such as "non-version message before + # version handshake". + ver_conn = self.nodes[0].add_outbound_p2p_connection(VersionSender(), p2p_idx=6, connection_type="outbound-full-relay", supports_v2_p2p=False, advertise_v2_p2p=False) + ver_conn.sync_with_ping() + + if __name__ == '__main__': - P2PAddConnections().main() + P2PAddConnections(__file__).main() diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index d10e47e036..56a9e6a84e 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -441,4 +441,4 @@ class AddrTest(BitcoinTestFramework): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_addrfetch.py b/test/functional/p2p_addrfetch.py index 3ead653ba6..69cc106341 100755 --- a/test/functional/p2p_addrfetch.py +++ b/test/functional/p2p_addrfetch.py @@ -83,4 +83,4 @@ class P2PAddrFetch(BitcoinTestFramework): if __name__ == '__main__': - P2PAddrFetch().main() + P2PAddrFetch(__file__).main() diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py index 4ec8e0bc04..d5ded926d3 100755 --- a/test/functional/p2p_addrv2_relay.py +++ b/test/functional/p2p_addrv2_relay.py @@ -110,4 +110,4 @@ class AddrTest(BitcoinTestFramework): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_block_sync.py b/test/functional/p2p_block_sync.py index 6c7f08364e..51bbac1738 100755 --- a/test/functional/p2p_block_sync.py +++ b/test/functional/p2p_block_sync.py @@ -34,4 +34,4 @@ class BlockSyncTest(BitcoinTestFramework): if __name__ == '__main__': - BlockSyncTest().main() + BlockSyncTest(__file__).main() diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index 680fa9c7fa..88d5aa1408 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -282,4 +282,4 @@ def compute_last_header(prev_header, hashes): if __name__ == '__main__': - CompactFiltersTest().main() + CompactFiltersTest(__file__).main() diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 637644e6e4..b9e6dc9056 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -125,4 +125,4 @@ class P2PBlocksOnly(BitcoinTestFramework): if __name__ == '__main__': - P2PBlocksOnly().main() + P2PBlocksOnly(__file__).main() diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 9e314db110..49cf26d425 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -965,4 +965,4 @@ class CompactBlocksTest(BitcoinTestFramework): if __name__ == '__main__': - CompactBlocksTest().main() + CompactBlocksTest(__file__).main() diff --git a/test/functional/p2p_compactblocks_blocksonly.py b/test/functional/p2p_compactblocks_blocksonly.py index 761cd3a218..b92efc875c 100755 --- a/test/functional/p2p_compactblocks_blocksonly.py +++ b/test/functional/p2p_compactblocks_blocksonly.py @@ -127,4 +127,4 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework): p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2)) if __name__ == '__main__': - P2PCompactBlocksBlocksOnly().main() + P2PCompactBlocksBlocksOnly(__file__).main() diff --git a/test/functional/p2p_compactblocks_hb.py b/test/functional/p2p_compactblocks_hb.py index 023b33ff6d..e4f58e9cf7 100755 --- a/test/functional/p2p_compactblocks_hb.py +++ b/test/functional/p2p_compactblocks_hb.py @@ -97,4 +97,4 @@ class CompactBlocksConnectionTest(BitcoinTestFramework): if __name__ == '__main__': - CompactBlocksConnectionTest().main() + CompactBlocksConnectionTest(__file__).main() diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index e47f9c732b..94be86475e 100755 --- a/test/functional/p2p_disconnect_ban.py +++ b/test/functional/p2p_disconnect_ban.py @@ -147,4 +147,4 @@ class DisconnectBanTest(BitcoinTestFramework): assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] if __name__ == '__main__': - DisconnectBanTest().main() + DisconnectBanTest(__file__).main() diff --git a/test/functional/p2p_dns_seeds.py b/test/functional/p2p_dns_seeds.py index e58ad8e0fc..a2d4ea110f 100755 --- a/test/functional/p2p_dns_seeds.py +++ b/test/functional/p2p_dns_seeds.py @@ -126,4 +126,4 @@ class P2PDNSSeeds(BitcoinTestFramework): if __name__ == '__main__': - P2PDNSSeeds().main() + P2PDNSSeeds(__file__).main() diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py index 4b4346af49..fbb5d716f5 100755 --- a/test/functional/p2p_dos_header_tree.py +++ b/test/functional/p2p_dos_header_tree.py @@ -85,4 +85,4 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): if __name__ == '__main__': - RejectLowDifficultyHeadersTest().main() + RejectLowDifficultyHeadersTest(__file__).main() diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py index 8b31dfa549..0d2bdcc429 100755 --- a/test/functional/p2p_eviction.py +++ b/test/functional/p2p_eviction.py @@ -124,4 +124,4 @@ class P2PEvict(BitcoinTestFramework): if __name__ == '__main__': - P2PEvict().main() + P2PEvict(__file__).main() diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index bcba534f9a..6b44118467 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -132,4 +132,4 @@ class FeeFilterTest(BitcoinTestFramework): if __name__ == '__main__': - FeeFilterTest().main() + FeeFilterTest(__file__).main() diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index 7c8ed58e51..e4aaf507cf 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -252,4 +252,4 @@ class FilterTest(BitcoinTestFramework): if __name__ == '__main__': - FilterTest().main() + FilterTest(__file__).main() diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index e8bba8555f..f49be62056 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -130,4 +130,4 @@ class P2PFingerprintTest(BitcoinTestFramework): if __name__ == '__main__': - P2PFingerprintTest().main() + P2PFingerprintTest(__file__).main() diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py index 60b43c32ae..6626b14ee0 100755 --- a/test/functional/p2p_getaddr_caching.py +++ b/test/functional/p2p_getaddr_caching.py @@ -119,4 +119,4 @@ class AddrTest(BitcoinTestFramework): if __name__ == '__main__': - AddrTest().main() + AddrTest(__file__).main() diff --git a/test/functional/p2p_getdata.py b/test/functional/p2p_getdata.py index 89d68d5ba0..6153d08d9b 100755 --- a/test/functional/p2p_getdata.py +++ b/test/functional/p2p_getdata.py @@ -46,4 +46,4 @@ class GetdataTest(BitcoinTestFramework): if __name__ == '__main__': - GetdataTest().main() + GetdataTest(__file__).main() diff --git a/test/functional/p2p_handshake.py b/test/functional/p2p_handshake.py index 21959ae522..18307a2824 100755 --- a/test/functional/p2p_handshake.py +++ b/test/functional/p2p_handshake.py @@ -17,6 +17,7 @@ from test_framework.messages import ( NODE_WITNESS, ) from test_framework.p2p import P2PInterface +from test_framework.util import p2p_port # Desirable service flags for outbound non-pruned and pruned peers. Note that @@ -88,10 +89,12 @@ class P2PHandshakeTest(BitcoinTestFramework): with node.assert_debug_log([f"feeler connection completed"]): self.add_outbound_connection(node, "feeler", NODE_NONE, wait_for_disconnect=True) - # TODO: re-add test introduced in commit 5d2fb14bafe4e80c0a482d99e5ebde07c477f000 - # ("test: p2p: check that connecting to ourself leads to disconnect") once - # the race condition causing issue #30368 is fixed + self.log.info("Check that connecting to ourself leads to immediate disconnect") + with node.assert_debug_log(["connected to self", "disconnecting"]): + node_listen_addr = f"127.0.0.1:{p2p_port(0)}" + node.addconnection(node_listen_addr, "outbound-full-relay", self.options.v2transport) + self.wait_until(lambda: len(node.getpeerinfo()) == 0) if __name__ == '__main__': - P2PHandshakeTest().main() + P2PHandshakeTest(__file__).main() diff --git a/test/functional/p2p_headers_sync_with_minchainwork.py b/test/functional/p2p_headers_sync_with_minchainwork.py index 832fd7e0e9..9055232cf3 100755 --- a/test/functional/p2p_headers_sync_with_minchainwork.py +++ b/test/functional/p2p_headers_sync_with_minchainwork.py @@ -162,4 +162,4 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): if __name__ == '__main__': - RejectLowDifficultyHeadersTest().main() + RejectLowDifficultyHeadersTest(__file__).main() diff --git a/test/functional/p2p_i2p_ports.py b/test/functional/p2p_i2p_ports.py index 20dcb50a57..b1a3c61c7a 100755 --- a/test/functional/p2p_i2p_ports.py +++ b/test/functional/p2p_i2p_ports.py @@ -32,4 +32,4 @@ class I2PPorts(BitcoinTestFramework): if __name__ == '__main__': - I2PPorts().main() + I2PPorts(__file__).main() diff --git a/test/functional/p2p_i2p_sessions.py b/test/functional/p2p_i2p_sessions.py index 9e7fdc6e14..67474f6c0e 100755 --- a/test/functional/p2p_i2p_sessions.py +++ b/test/functional/p2p_i2p_sessions.py @@ -33,4 +33,4 @@ class I2PSessions(BitcoinTestFramework): if __name__ == '__main__': - I2PSessions().main() + I2PSessions(__file__).main() diff --git a/test/functional/p2p_ibd_stalling.py b/test/functional/p2p_ibd_stalling.py index 830f374d63..11cd8837f4 100755 --- a/test/functional/p2p_ibd_stalling.py +++ b/test/functional/p2p_ibd_stalling.py @@ -162,4 +162,4 @@ class P2PIBDStallingTest(BitcoinTestFramework): if __name__ == '__main__': - P2PIBDStallingTest().main() + P2PIBDStallingTest(__file__).main() diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py index b93e39a925..882f5b5c13 100755 --- a/test/functional/p2p_ibd_txrelay.py +++ b/test/functional/p2p_ibd_txrelay.py @@ -86,4 +86,4 @@ class P2PIBDTxRelayTest(BitcoinTestFramework): peer_txer.send_and_ping(msg_tx(tx)) if __name__ == '__main__': - P2PIBDTxRelayTest().main() + P2PIBDTxRelayTest(__file__).main() diff --git a/test/functional/p2p_initial_headers_sync.py b/test/functional/p2p_initial_headers_sync.py index bc6e0fb355..5c17b75677 100755 --- a/test/functional/p2p_initial_headers_sync.py +++ b/test/functional/p2p_initial_headers_sync.py @@ -96,5 +96,5 @@ class HeadersSyncTest(BitcoinTestFramework): self.log.info("Success!") if __name__ == '__main__': - HeadersSyncTest().main() + HeadersSyncTest(__file__).main() diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index 8ec62ae5ee..c4c79dcbb8 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -138,4 +138,4 @@ class InvalidBlockRequestTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidBlockRequestTest().main() + InvalidBlockRequestTest(__file__).main() diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 32a23532a2..bde01d5c95 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -39,4 +39,4 @@ class InvalidLocatorTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidLocatorTest().main() + InvalidLocatorTest(__file__).main() diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index 8e459ba676..507393fb70 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -356,4 +356,4 @@ class InvalidMessagesTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidMessagesTest().main() + InvalidMessagesTest(__file__).main() diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index 0ae05d4b0b..241aefab24 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -224,4 +224,4 @@ class InvalidTxRequestTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidTxRequestTest().main() + InvalidTxRequestTest(__file__).main() diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 645488f24d..f800e815d8 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -178,4 +178,4 @@ class P2PLeakTest(BitcoinTestFramework): if __name__ == '__main__': - P2PLeakTest().main() + P2PLeakTest(__file__).main() diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index f53f98e06d..a2eec49b72 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -104,4 +104,4 @@ class P2PLeakTxTest(BitcoinTestFramework): if __name__ == '__main__': - P2PLeakTxTest().main() + P2PLeakTxTest(__file__).main() diff --git a/test/functional/p2p_message_capture.py b/test/functional/p2p_message_capture.py index 691a0b6409..4c82adc58c 100755 --- a/test/functional/p2p_message_capture.py +++ b/test/functional/p2p_message_capture.py @@ -69,4 +69,4 @@ class MessageCaptureTest(BitcoinTestFramework): if __name__ == '__main__': - MessageCaptureTest().main() + MessageCaptureTest(__file__).main() diff --git a/test/functional/p2p_mutated_blocks.py b/test/functional/p2p_mutated_blocks.py index 708b19b1e5..4a790168da 100755 --- a/test/functional/p2p_mutated_blocks.py +++ b/test/functional/p2p_mutated_blocks.py @@ -112,4 +112,4 @@ class MutatedBlocksTest(BitcoinTestFramework): if __name__ == '__main__': - MutatedBlocksTest().main() + MutatedBlocksTest(__file__).main() diff --git a/test/functional/p2p_net_deadlock.py b/test/functional/p2p_net_deadlock.py index 1a357b944b..4f1b731e21 100755 --- a/test/functional/p2p_net_deadlock.py +++ b/test/functional/p2p_net_deadlock.py @@ -34,4 +34,4 @@ class NetDeadlockTest(BitcoinTestFramework): if __name__ == '__main__': - NetDeadlockTest().main() + NetDeadlockTest(__file__).main() diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py index 507a71b2a9..dd2dc9ae69 100755 --- a/test/functional/p2p_nobloomfilter_messages.py +++ b/test/functional/p2p_nobloomfilter_messages.py @@ -45,4 +45,4 @@ class P2PNoBloomFilterMessages(BitcoinTestFramework): if __name__ == '__main__': - P2PNoBloomFilterMessages().main() + P2PNoBloomFilterMessages(__file__).main() diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index 8b63d8ee26..df6e6a2e28 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -172,4 +172,4 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): self.test_avoid_requesting_historical_blocks() if __name__ == '__main__': - NodeNetworkLimitedTest().main() + NodeNetworkLimitedTest(__file__).main() diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index aec6e95fbc..4477046c8d 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -412,4 +412,4 @@ class PackageRelayTest(BitcoinTestFramework): if __name__ == '__main__': - PackageRelayTest().main() + PackageRelayTest(__file__).main() diff --git a/test/functional/p2p_orphan_handling.py b/test/functional/p2p_orphan_handling.py index f525d87cca..22600bf8a4 100755 --- a/test/functional/p2p_orphan_handling.py +++ b/test/functional/p2p_orphan_handling.py @@ -585,4 +585,4 @@ class OrphanHandlingTest(BitcoinTestFramework): if __name__ == '__main__': - OrphanHandlingTest().main() + OrphanHandlingTest(__file__).main() diff --git a/test/functional/p2p_outbound_eviction.py b/test/functional/p2p_outbound_eviction.py index 8d89688999..30ac85e32f 100755 --- a/test/functional/p2p_outbound_eviction.py +++ b/test/functional/p2p_outbound_eviction.py @@ -250,4 +250,4 @@ class P2POutEvict(BitcoinTestFramework): if __name__ == '__main__': - P2POutEvict().main() + P2POutEvict(__file__).main() diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 80a27943fd..c881dd6ff4 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -119,14 +119,17 @@ class P2PPermissionsTests(BitcoinTestFramework): self.log.debug("Check that node[1] will not send an invalid tx to node[0]") tx.vout[0].nValue += 1 + # add dust to cause policy rejection but no disconnection + tx.vout.append(tx.vout[0]) + tx.vout[-1].nValue = 0 txid = tx.rehash() # Send the transaction twice. The first time, it'll be rejected by ATMP because it conflicts - # with a mempool transaction. The second time, it'll be in the m_recent_rejects filter. + # with a mempool transaction. The second time, it'll be in the m_lazy_recent_rejects filter. p2p_rebroadcast_wallet.send_txs_and_test( [tx], self.nodes[1], success=False, - reject_reason='{} (wtxid={}) from peer=0 was not accepted: txn-mempool-conflict'.format(txid, tx.getwtxid()) + reject_reason='{} (wtxid={}) from peer=0 was not accepted: dust'.format(txid, tx.getwtxid()) ) p2p_rebroadcast_wallet.send_txs_and_test( @@ -147,4 +150,4 @@ class P2PPermissionsTests(BitcoinTestFramework): if __name__ == '__main__': - P2PPermissionsTests().main() + P2PPermissionsTests(__file__).main() diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py index 3ba30a42b1..5c10ac2a4b 100755 --- a/test/functional/p2p_ping.py +++ b/test/functional/p2p_ping.py @@ -117,4 +117,4 @@ class PingPongTest(BitcoinTestFramework): if __name__ == '__main__': - PingPongTest().main() + PingPongTest(__file__).main() diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index d20cf41a72..9be53d2ab8 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -2067,4 +2067,4 @@ class SegWitTest(BitcoinTestFramework): if __name__ == '__main__': - SegWitTest().main() + SegWitTest(__file__).main() diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 5c463267a1..db706556d8 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -568,4 +568,4 @@ class SendHeadersTest(BitcoinTestFramework): assert "getdata" not in inv_node.last_message if __name__ == '__main__': - SendHeadersTest().main() + SendHeadersTest(__file__).main() diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py index 8f5e6c0387..2c7216b5ca 100755 --- a/test/functional/p2p_sendtxrcncl.py +++ b/test/functional/p2p_sendtxrcncl.py @@ -232,4 +232,4 @@ class SendTxRcnclTest(BitcoinTestFramework): if __name__ == '__main__': - SendTxRcnclTest().main() + SendTxRcnclTest(__file__).main() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index 80d7b6e9ae..1fd78e163b 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -109,4 +109,4 @@ class TimeoutsTest(BitcoinTestFramework): if __name__ == '__main__': - TimeoutsTest().main() + TimeoutsTest(__file__).main() diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index 0af6b1d2c9..11b4d9cc3b 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -306,4 +306,4 @@ class TxDownloadTest(BitcoinTestFramework): if __name__ == '__main__': - TxDownloadTest().main() + TxDownloadTest(__file__).main() diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py index e674f6c3eb..afe9df8a0f 100755 --- a/test/functional/p2p_tx_privacy.py +++ b/test/functional/p2p_tx_privacy.py @@ -74,4 +74,4 @@ class TxPrivacyTest(BitcoinTestFramework): spy.wait_for_inv_match(CInv(MSG_WTX, tx2.calc_sha256(True))) if __name__ == '__main__': - TxPrivacyTest().main() + TxPrivacyTest(__file__).main() diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 776eaf5255..835ecbf184 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -296,4 +296,4 @@ class AcceptBlockTest(BitcoinTestFramework): self.log.info("Successfully synced nodes 1 and 0") if __name__ == '__main__': - AcceptBlockTest().main() + AcceptBlockTest(__file__).main() diff --git a/test/functional/p2p_v2_earlykeyresponse.py b/test/functional/p2p_v2_earlykeyresponse.py deleted file mode 100755 index 32d2e1148a..0000000000 --- a/test/functional/p2p_v2_earlykeyresponse.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/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. - -import random - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.crypto.ellswift import ellswift_create -from test_framework.p2p import P2PInterface -from test_framework.v2_p2p import EncryptedP2PState - - -class TestEncryptedP2PState(EncryptedP2PState): - """ Modify v2 P2P protocol functions for testing that "The responder waits until one byte is received which does - not match the 16 bytes consisting of the network magic followed by "version\x00\x00\x00\x00\x00"." (see BIP 324) - - - if `send_net_magic` is True, send first 4 bytes of ellswift (match network magic) else send remaining 60 bytes - - `can_data_be_received` is a variable used to assert if data is received on recvbuf. - - v2 TestNode shouldn't respond back if we send V1_PREFIX and data shouldn't be received on recvbuf. - This state is represented using `can_data_be_received` = False. - - v2 TestNode responds back when mismatch from V1_PREFIX happens and data can be received on recvbuf. - This state is represented using `can_data_be_received` = True. - """ - - def __init__(self): - super().__init__(initiating=True, net='regtest') - self.send_net_magic = True - self.can_data_be_received = False - - def initiate_v2_handshake(self, garbage_len=random.randrange(4096)): - """Initiator begins the v2 handshake by sending its ellswift bytes and garbage. - Here, the 64 bytes ellswift is assumed to have it's 4 bytes match network magic bytes. It is sent in 2 phases: - 1. when `send_network_magic` = True, send first 4 bytes of ellswift (matches network magic bytes) - 2. when `send_network_magic` = False, send remaining 60 bytes of ellswift - """ - if self.send_net_magic: - self.privkey_ours, self.ellswift_ours = ellswift_create() - self.sent_garbage = random.randbytes(garbage_len) - self.send_net_magic = False - return b"\xfa\xbf\xb5\xda" - else: - self.can_data_be_received = True - return self.ellswift_ours[4:] + self.sent_garbage - - -class PeerEarlyKey(P2PInterface): - """Custom implementation of P2PInterface which uses modified v2 P2P protocol functions for testing purposes.""" - def __init__(self): - super().__init__() - self.v2_state = None - self.connection_opened = False - - def connection_made(self, transport): - """64 bytes ellswift is sent in 2 parts during `initial_v2_handshake()`""" - self.v2_state = TestEncryptedP2PState() - super().connection_made(transport) - - def data_received(self, t): - # check that data can be received on recvbuf only when mismatch from V1_PREFIX happens (send_net_magic = False) - assert self.v2_state.can_data_be_received and not self.v2_state.send_net_magic - - def on_open(self): - self.connection_opened = True - -class P2PEarlyKey(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 1 - self.extra_args = [["-v2transport=1", "-peertimeout=3"]] - - def run_test(self): - self.log.info('Sending ellswift bytes in parts to ensure that response from responder is received only when') - self.log.info('ellswift bytes have a mismatch from the 16 bytes(network magic followed by "version\\x00\\x00\\x00\\x00\\x00")') - node0 = self.nodes[0] - self.log.info('Sending first 4 bytes of ellswift which match network magic') - self.log.info('If a response is received, assertion failure would happen in our custom data_received() function') - # send happens in `initiate_v2_handshake()` in `connection_made()` - peer1 = node0.add_p2p_connection(PeerEarlyKey(), wait_for_verack=False, send_version=False, supports_v2_p2p=True, wait_for_v2_handshake=False) - self.wait_until(lambda: peer1.connection_opened) - self.log.info('Sending remaining ellswift and garbage which are different from V1_PREFIX. Since a response is') - self.log.info('expected now, our custom data_received() function wouldn\'t result in assertion failure') - ellswift_and_garbage_data = peer1.v2_state.initiate_v2_handshake() - peer1.send_raw_message(ellswift_and_garbage_data) - peer1.wait_for_disconnect(timeout=5) - self.log.info('successful disconnection when MITM happens in the key exchange phase') - - -if __name__ == '__main__': - P2PEarlyKey().main() diff --git a/test/functional/p2p_v2_encrypted.py b/test/functional/p2p_v2_encrypted.py index 05755dece0..3e8ce09d24 100755 --- a/test/functional/p2p_v2_encrypted.py +++ b/test/functional/p2p_v2_encrypted.py @@ -131,4 +131,4 @@ class P2PEncrypted(BitcoinTestFramework): if __name__ == '__main__': - P2PEncrypted().main() + P2PEncrypted(__file__).main() diff --git a/test/functional/p2p_v2_misbehaving.py b/test/functional/p2p_v2_misbehaving.py new file mode 100755 index 0000000000..0af96a4f8c --- /dev/null +++ b/test/functional/p2p_v2_misbehaving.py @@ -0,0 +1,189 @@ +#!/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. + +import random +import time +from enum import Enum + +from test_framework.messages import MAGIC_BYTES +from test_framework.p2p import P2PInterface +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import random_bitflip +from test_framework.v2_p2p import ( + EncryptedP2PState, + MAX_GARBAGE_LEN, +) + + +class TestType(Enum): + """ Scenarios to be tested: + + 1. EARLY_KEY_RESPONSE - The responder needs to wait until one byte is received which does not match the 16 bytes + consisting of network magic followed by "version\x00\x00\x00\x00\x00" before sending out its ellswift + garbage bytes + 2. EXCESS_GARBAGE - Disconnection happens when > MAX_GARBAGE_LEN bytes garbage is sent + 3. WRONG_GARBAGE_TERMINATOR - Disconnection happens when incorrect garbage terminator is sent + 4. WRONG_GARBAGE - Disconnection happens when garbage bytes that is sent is different from what the peer receives + 5. SEND_NO_AAD - Disconnection happens when AAD of first encrypted packet after the garbage terminator is not filled + 6. SEND_NON_EMPTY_VERSION_PACKET - non-empty version packet is simply ignored + """ + EARLY_KEY_RESPONSE = 0 + EXCESS_GARBAGE = 1 + WRONG_GARBAGE_TERMINATOR = 2 + WRONG_GARBAGE = 3 + SEND_NO_AAD = 4 + SEND_NON_EMPTY_VERSION_PACKET = 5 + + +class EarlyKeyResponseState(EncryptedP2PState): + """ Modify v2 P2P protocol functions for testing EARLY_KEY_RESPONSE scenario""" + def __init__(self, initiating, net): + super().__init__(initiating=initiating, net=net) + self.can_data_be_received = False # variable used to assert if data is received on recvbuf. + + def initiate_v2_handshake(self): + """Send ellswift and garbage bytes in 2 parts when TestType = (EARLY_KEY_RESPONSE)""" + self.generate_keypair_and_garbage() + return b"" + + +class ExcessGarbageState(EncryptedP2PState): + """Generate > MAX_GARBAGE_LEN garbage bytes""" + def generate_keypair_and_garbage(self): + garbage_len = MAX_GARBAGE_LEN + random.randrange(1, MAX_GARBAGE_LEN + 1) + return super().generate_keypair_and_garbage(garbage_len) + + +class WrongGarbageTerminatorState(EncryptedP2PState): + """Add option for sending wrong garbage terminator""" + def generate_keypair_and_garbage(self): + garbage_len = random.randrange(MAX_GARBAGE_LEN//2) + return super().generate_keypair_and_garbage(garbage_len) + + def complete_handshake(self, response): + length, handshake_bytes = super().complete_handshake(response) + # first 16 bytes returned by complete_handshake() is the garbage terminator + wrong_garbage_terminator = random_bitflip(handshake_bytes[:16]) + return length, wrong_garbage_terminator + handshake_bytes[16:] + + +class WrongGarbageState(EncryptedP2PState): + """Generate tampered garbage bytes""" + def generate_keypair_and_garbage(self): + garbage_len = random.randrange(1, MAX_GARBAGE_LEN) + ellswift_garbage_bytes = super().generate_keypair_and_garbage(garbage_len) + # assume that garbage bytes sent to TestNode were tampered with + return ellswift_garbage_bytes[:64] + random_bitflip(ellswift_garbage_bytes[64:]) + + +class NoAADState(EncryptedP2PState): + """Add option for not filling first encrypted packet after garbage terminator with AAD""" + def generate_keypair_and_garbage(self): + garbage_len = random.randrange(1, MAX_GARBAGE_LEN) + return super().generate_keypair_and_garbage(garbage_len) + + def complete_handshake(self, response): + self.sent_garbage = b'' # do not authenticate the garbage which is sent + return super().complete_handshake(response) + + +class NonEmptyVersionPacketState(EncryptedP2PState): + """"Add option for sending non-empty transport version packet.""" + def complete_handshake(self, response): + self.transport_version = random.randbytes(5) + return super().complete_handshake(response) + + +class MisbehavingV2Peer(P2PInterface): + """Custom implementation of P2PInterface which uses modified v2 P2P protocol functions for testing purposes.""" + def __init__(self, test_type): + super().__init__() + self.test_type = test_type + + def connection_made(self, transport): + if self.test_type == TestType.EARLY_KEY_RESPONSE: + self.v2_state = EarlyKeyResponseState(initiating=True, net='regtest') + elif self.test_type == TestType.EXCESS_GARBAGE: + self.v2_state = ExcessGarbageState(initiating=True, net='regtest') + elif self.test_type == TestType.WRONG_GARBAGE_TERMINATOR: + self.v2_state = WrongGarbageTerminatorState(initiating=True, net='regtest') + elif self.test_type == TestType.WRONG_GARBAGE: + self.v2_state = WrongGarbageState(initiating=True, net='regtest') + elif self.test_type == TestType.SEND_NO_AAD: + self.v2_state = NoAADState(initiating=True, net='regtest') + elif TestType.SEND_NON_EMPTY_VERSION_PACKET: + self.v2_state = NonEmptyVersionPacketState(initiating=True, net='regtest') + super().connection_made(transport) + + def data_received(self, t): + if self.test_type == TestType.EARLY_KEY_RESPONSE: + # check that data can be received on recvbuf only when mismatch from V1_PREFIX happens + assert self.v2_state.can_data_be_received + else: + super().data_received(t) + + +class EncryptedP2PMisbehaving(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.extra_args = [["-v2transport=1", "-peertimeout=3"]] + + def run_test(self): + self.test_earlykeyresponse() + self.test_v2disconnection() + + def test_earlykeyresponse(self): + self.log.info('Sending ellswift bytes in parts to ensure that response from responder is received only when') + self.log.info('ellswift bytes have a mismatch from the 16 bytes(network magic followed by "version\\x00\\x00\\x00\\x00\\x00")') + node0 = self.nodes[0] + node0.setmocktime(int(time.time())) + self.log.info('Sending first 4 bytes of ellswift which match network magic') + self.log.info('If a response is received, assertion failure would happen in our custom data_received() function') + with node0.wait_for_new_peer(): + peer1 = node0.add_p2p_connection(MisbehavingV2Peer(TestType.EARLY_KEY_RESPONSE), wait_for_verack=False, send_version=False, supports_v2_p2p=True, wait_for_v2_handshake=False) + peer1.send_raw_message(MAGIC_BYTES['regtest']) + self.log.info('Sending remaining ellswift and garbage which are different from V1_PREFIX. Since a response is') + self.log.info('expected now, our custom data_received() function wouldn\'t result in assertion failure') + peer1.v2_state.can_data_be_received = True + self.wait_until(lambda: peer1.v2_state.ellswift_ours) + peer1.send_raw_message(peer1.v2_state.ellswift_ours[4:] + peer1.v2_state.sent_garbage) + # Ensure that the bytes sent after 4 bytes network magic are actually received. + self.wait_until(lambda: node0.getpeerinfo()[-1]["bytesrecv"] > 4) + self.wait_until(lambda: node0.getpeerinfo()[-1]["bytessent"] > 0) + with node0.assert_debug_log(['V2 handshake timeout peer=0']): + node0.bumpmocktime(4) # `InactivityCheck()` triggers now + peer1.wait_for_disconnect(timeout=1) + self.log.info('successful disconnection since modified ellswift was sent as response') + + def test_v2disconnection(self): + # test v2 disconnection scenarios + node0 = self.nodes[0] + expected_debug_message = [ + [], # EARLY_KEY_RESPONSE + ["V2 transport error: missing garbage terminator, peer=1"], # EXCESS_GARBAGE + ["V2 handshake timeout peer=3"], # WRONG_GARBAGE_TERMINATOR + ["V2 transport error: packet decryption failure"], # WRONG_GARBAGE + ["V2 transport error: packet decryption failure"], # SEND_NO_AAD + [], # SEND_NON_EMPTY_VERSION_PACKET + ] + for test_type in TestType: + if test_type == TestType.EARLY_KEY_RESPONSE: + continue + elif test_type == TestType.SEND_NON_EMPTY_VERSION_PACKET: + node0.add_p2p_connection(MisbehavingV2Peer(test_type), wait_for_verack=True, send_version=True, supports_v2_p2p=True) + self.log.info(f"No disconnection for {test_type.name}") + else: + with node0.assert_debug_log(expected_debug_message[test_type.value], timeout=5): + node0.setmocktime(int(time.time())) + peer1 = node0.add_p2p_connection(MisbehavingV2Peer(test_type), wait_for_verack=False, send_version=False, supports_v2_p2p=True, expect_success=False) + # Make a passing connection for more robust disconnection checking. + peer2 = node0.add_p2p_connection(P2PInterface()) + assert peer2.is_connected + node0.bumpmocktime(4) # `InactivityCheck()` triggers now + peer1.wait_for_disconnect() + self.log.info(f"Expected disconnection for {test_type.name}") + + +if __name__ == '__main__': + EncryptedP2PMisbehaving(__file__).main() diff --git a/test/functional/p2p_v2_transport.py b/test/functional/p2p_v2_transport.py index fe2449124d..94c91906e6 100755 --- a/test/functional/p2p_v2_transport.py +++ b/test/functional/p2p_v2_transport.py @@ -168,4 +168,4 @@ class V2TransportTest(BitcoinTestFramework): if __name__ == '__main__': - V2TransportTest().main() + V2TransportTest(__file__).main() diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py index 3106419e5c..8c76c1f5f5 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -124,4 +124,4 @@ class RPCBindTest(BitcoinTestFramework): assert_raises_rpc_error(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], self.non_loopback_ip, self.defaultport) if __name__ == '__main__': - RPCBindTest().main() + RPCBindTest(__file__).main() diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 9b7743cafa..e5aca7f138 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -635,4 +635,4 @@ class BlockchainTest(BitcoinTestFramework): if __name__ == '__main__': - BlockchainTest().main() + BlockchainTest(__file__).main() diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 37656341d2..9f4e17a328 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -257,4 +257,4 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): if __name__ == '__main__': - RpcCreateMultiSigTest().main() + RpcCreateMultiSigTest(__file__).main() diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py index f37e61ab50..4f127fa8b7 100755 --- a/test/functional/rpc_decodescript.py +++ b/test/functional/rpc_decodescript.py @@ -187,6 +187,16 @@ class DecodeScriptTest(BitcoinTestFramework): assert_equal('1 ' + xonly_public_key, rpc_result['asm']) assert 'segwit' not in rpc_result + self.log.info("- P2A (anchor)") + # 1 <4e73> + witprog_hex = '4e73' + rpc_result = self.nodes[0].decodescript('5102' + witprog_hex) + assert_equal('anchor', rpc_result['type']) + # in the disassembly, the witness program is shown as single decimal due to its small size + witprog_as_decimal = int.from_bytes(bytes.fromhex(witprog_hex), 'little') + assert_equal(f'1 {witprog_as_decimal}', rpc_result['asm']) + assert_equal('bcrt1pfeesnyr2tx', rpc_result['address']) + def decoderawtransaction_asm_sighashtype(self): """Test decoding scripts via RPC command "decoderawtransaction". @@ -289,4 +299,4 @@ class DecodeScriptTest(BitcoinTestFramework): self.decodescript_miniscript() if __name__ == '__main__': - DecodeScriptTest().main() + DecodeScriptTest(__file__).main() diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py index 15c77ed856..4a415d57f5 100755 --- a/test/functional/rpc_deprecated.py +++ b/test/functional/rpc_deprecated.py @@ -26,4 +26,4 @@ class DeprecatedRpcTest(BitcoinTestFramework): self.log.info("No tested deprecated RPC methods") if __name__ == '__main__': - DeprecatedRpcTest().main() + DeprecatedRpcTest(__file__).main() diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py index 64994d6bb3..c66d91713f 100755 --- a/test/functional/rpc_deriveaddresses.py +++ b/test/functional/rpc_deriveaddresses.py @@ -61,4 +61,4 @@ class DeriveaddressesTest(BitcoinTestFramework): assert_raises_rpc_error(-5, "Descriptor does not have a corresponding address", self.nodes[0].deriveaddresses, bare_multisig_descriptor) if __name__ == '__main__': - DeriveaddressesTest().main() + DeriveaddressesTest(__file__).main() diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py index c92c8da357..aa12da6ceb 100755 --- a/test/functional/rpc_dumptxoutset.py +++ b/test/functional/rpc_dumptxoutset.py @@ -43,7 +43,7 @@ class DumptxoutsetTest(BitcoinTestFramework): # UTXO snapshot hash should be deterministic based on mocked time. assert_equal( sha256sum_file(str(expected_path)).hex(), - '2f775f82811150d310527b5ff773f81fb0fb517e941c543c1f7c4d38fd2717b3') + '31fcdd0cf542a4b1dfc13c3c05106620ce48951ef62907dd8e5e8c15a0aa993b') assert_equal( out['txoutset_hash'], 'a0b7baa3bf5ccbd3279728f230d7ca0c44a76e9923fca8f32dbfd08d65ea496a') @@ -58,4 +58,4 @@ class DumptxoutsetTest(BitcoinTestFramework): if __name__ == '__main__': - DumptxoutsetTest().main() + DumptxoutsetTest(__file__).main() diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index 6643799a76..05ceafbe4e 100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py @@ -52,4 +52,4 @@ class EstimateFeeTest(BitcoinTestFramework): if __name__ == '__main__': - EstimateFeeTest().main() + EstimateFeeTest(__file__).main() diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 3e250925e7..68de900664 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -126,4 +126,4 @@ class RPCGenerateTest(BitcoinTestFramework): if __name__ == "__main__": - RPCGenerateTest().main() + RPCGenerateTest(__file__).main() diff --git a/test/functional/rpc_getblockfilter.py b/test/functional/rpc_getblockfilter.py index b09af9e078..245bcec8e8 100755 --- a/test/functional/rpc_getblockfilter.py +++ b/test/functional/rpc_getblockfilter.py @@ -61,4 +61,4 @@ class GetBlockFilterTest(BitcoinTestFramework): self.nodes[0].getblockfilter, genesis_hash, filter_type) if __name__ == '__main__': - GetBlockFilterTest().main() + GetBlockFilterTest(__file__).main() diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index 1ab1023cf1..e309018516 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -154,4 +154,4 @@ class GetBlockFromPeerTest(BitcoinTestFramework): if __name__ == '__main__': - GetBlockFromPeerTest().main() + GetBlockFromPeerTest(__file__).main() diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index bf261befcc..d1e4895eb6 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -183,4 +183,4 @@ class GetblockstatsTest(BitcoinTestFramework): assert_equal(tip_stats["utxo_size_inc_actual"], 300) if __name__ == '__main__': - GetblockstatsTest().main() + GetblockstatsTest(__file__).main() diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py index 7efa306c8c..1bd4413ce1 100755 --- a/test/functional/rpc_getchaintips.py +++ b/test/functional/rpc_getchaintips.py @@ -58,4 +58,4 @@ class GetChainTipsTest (BitcoinTestFramework): assert_equal (tips[1], shortTip) if __name__ == '__main__': - GetChainTipsTest ().main () + GetChainTipsTest(__file__).main() diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py index 2eb36f260c..c84928462d 100755 --- a/test/functional/rpc_getdescriptorinfo.py +++ b/test/functional/rpc_getdescriptorinfo.py @@ -63,4 +63,4 @@ class DescriptorTest(BitcoinTestFramework): if __name__ == '__main__': - DescriptorTest().main() + DescriptorTest(__file__).main() diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index 53c5aa05e5..4ce24ecb67 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -132,4 +132,4 @@ class HelpRpcTest(BitcoinTestFramework): if __name__ == '__main__': - HelpRpcTest().main() + HelpRpcTest(__file__).main() diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py index 6759b69dd1..07795534a0 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-2022 The Bitcoin Core developers +# Copyright (c) 2020-present 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.""" @@ -12,6 +12,7 @@ from test_framework.util import ( ) BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv' +BECH32_VALID_UNKNOWN_WITNESS = 'bcrt1p424qxxyd0r' BECH32_VALID_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U33RAH7R' BECH32_VALID_MULTISIG = 'bcrt1qdg3myrgvzw7ml9q0ejxhlkyxm7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks' @@ -80,6 +81,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework): # Valid Bech32 self.check_valid(BECH32_VALID) + self.check_valid(BECH32_VALID_UNKNOWN_WITNESS) self.check_valid(BECH32_VALID_CAPITALS) self.check_valid(BECH32_VALID_MULTISIG) @@ -109,6 +111,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework): 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) + assert "isscript" not in node.getaddressinfo(BECH32_VALID_UNKNOWN_WITNESS) def run_test(self): self.test_validateaddress() @@ -119,4 +122,4 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidAddressErrorMessageTest().main() + InvalidAddressErrorMessageTest(__file__).main() diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index 69c5397ce2..db79d55259 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -90,4 +90,4 @@ class InvalidateTest(BitcoinTestFramework): if __name__ == '__main__': - InvalidateTest().main() + InvalidateTest(__file__).main() diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py index 246af22e50..231d93a7b1 100755 --- a/test/functional/rpc_mempool_info.py +++ b/test/functional/rpc_mempool_info.py @@ -96,4 +96,4 @@ class RPCMempoolInfoTest(BitcoinTestFramework): if __name__ == '__main__': - RPCMempoolInfoTest().main() + RPCMempoolInfoTest(__file__).main() diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index 20485c01d3..b5c12b28c1 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -102,4 +102,4 @@ class RpcMiscTest(BitcoinTestFramework): if __name__ == '__main__': - RpcMiscTest().main() + RpcMiscTest(__file__).main() diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py index 46d9ffceae..0385c33267 100755 --- a/test/functional/rpc_named_arguments.py +++ b/test/functional/rpc_named_arguments.py @@ -35,4 +35,4 @@ class NamedArgumentTest(BitcoinTestFramework): 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() + NamedArgumentTest(__file__).main() diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 37e2c1fb71..b63059b1ee 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -574,4 +574,4 @@ class NetTest(BitcoinTestFramework): if __name__ == '__main__': - NetTest().main() + NetTest(__file__).main() diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index 1acd586d2c..ef2f66b3a0 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -489,4 +489,4 @@ class RPCPackagesTest(BitcoinTestFramework): assert_equal(node.getrawmempool(), [chained_txns_burn[0]["txid"]]) if __name__ == "__main__": - RPCPackagesTest().main() + RPCPackagesTest(__file__).main() diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index 3062a86565..224bba6f9b 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -109,4 +109,4 @@ class PreciousTest(BitcoinTestFramework): assert_equal(self.nodes[2].getbestblockhash(), hashH) if __name__ == '__main__': - PreciousTest().main() + PreciousTest(__file__).main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 6ee7e56886..8042bdf071 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -8,6 +8,9 @@ from decimal import Decimal from itertools import product from random import randbytes +from test_framework.blocktools import ( + MAX_STANDARD_TX_WEIGHT, +) from test_framework.descriptors import descsum_create from test_framework.key import H_POINT from test_framework.messages import ( @@ -16,6 +19,7 @@ from test_framework.messages import ( CTxIn, CTxOut, MAX_BIP125_RBF_SEQUENCE, + WITNESS_SCALE_FACTOR, ) from test_framework.psbt import ( PSBT, @@ -30,6 +34,7 @@ from test_framework.psbt import ( PSBT_OUT_TAP_TREE, ) from test_framework.script import CScript, OP_TRUE +from test_framework.script_util import MIN_STANDARD_TX_NONWITNESS_SIZE from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_approx, @@ -68,6 +73,28 @@ class PSBTTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def test_psbt_incomplete_after_invalid_modification(self): + self.log.info("Check that PSBT is correctly marked as incomplete after invalid modification") + node = self.nodes[2] + wallet = node.get_wallet_rpc(self.default_wallet_name) + address = wallet.getnewaddress() + wallet.sendtoaddress(address=address, amount=1.0) + self.generate(node, nblocks=1, sync_fun=lambda: self.sync_all(self.nodes[:2])) + + utxos = wallet.listunspent(addresses=[address]) + psbt = wallet.createpsbt([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{wallet.getnewaddress(): 0.9999}]) + signed_psbt = wallet.walletprocesspsbt(psbt)["psbt"] + + # Modify the raw transaction by changing the output address, so the signature is no longer valid + signed_psbt_obj = PSBT.from_base64(signed_psbt) + substitute_addr = wallet.getnewaddress() + raw = wallet.createrawtransaction([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{substitute_addr: 0.9999}]) + signed_psbt_obj.g.map[PSBT_GLOBAL_UNSIGNED_TX] = bytes.fromhex(raw) + + # Check that the walletprocesspsbt call succeeds but also recognizes that the transaction is not complete + signed_psbt_incomplete = wallet.walletprocesspsbt(signed_psbt_obj.to_base64(), finalize=False) + assert signed_psbt_incomplete["complete"] is False + def test_utxo_conversion(self): self.log.info("Check that non-witness UTXOs are removed for segwit v1+ inputs") mining_node = self.nodes[2] @@ -186,6 +213,46 @@ class PSBTTest(BitcoinTestFramework): # Create and fund a raw tx for sending 10 BTC psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt'] + self.log.info("Test for invalid maximum transaction weights") + dest_arg = [{self.nodes[0].getnewaddress(): 1}] + min_tx_weight = MIN_STANDARD_TX_NONWITNESS_SIZE * WITNESS_SCALE_FACTOR + assert_raises_rpc_error(-4, f"Maximum transaction weight must be between {min_tx_weight} and {MAX_STANDARD_TX_WEIGHT}", self.nodes[0].walletcreatefundedpsbt, [], dest_arg, 0, {"max_tx_weight": -1}) + assert_raises_rpc_error(-4, f"Maximum transaction weight must be between {min_tx_weight} and {MAX_STANDARD_TX_WEIGHT}", self.nodes[0].walletcreatefundedpsbt, [], dest_arg, 0, {"max_tx_weight": 0}) + assert_raises_rpc_error(-4, f"Maximum transaction weight must be between {min_tx_weight} and {MAX_STANDARD_TX_WEIGHT}", self.nodes[0].walletcreatefundedpsbt, [], dest_arg, 0, {"max_tx_weight": MAX_STANDARD_TX_WEIGHT + 1}) + + # Base transaction vsize: version (4) + locktime (4) + input count (1) + witness overhead (1) = 10 vbytes + base_tx_vsize = 10 + # One P2WPKH output vsize: outpoint (31 vbytes) + p2wpkh_output_vsize = 31 + # 1 vbyte for output count + output_count = 1 + tx_weight_without_inputs = (base_tx_vsize + output_count + p2wpkh_output_vsize) * WITNESS_SCALE_FACTOR + # min_tx_weight is greater than transaction weight without inputs + assert_greater_than(min_tx_weight, tx_weight_without_inputs) + + # In order to test for when the passed max weight is less than the transaction weight without inputs + # Define destination with two outputs. + dest_arg_large = [{self.nodes[0].getnewaddress(): 1}, {self.nodes[0].getnewaddress(): 1}] + large_tx_vsize_without_inputs = base_tx_vsize + output_count + (p2wpkh_output_vsize * 2) + large_tx_weight_without_inputs = large_tx_vsize_without_inputs * WITNESS_SCALE_FACTOR + assert_greater_than(large_tx_weight_without_inputs, min_tx_weight) + # Test for max_tx_weight less than Transaction weight without inputs + assert_raises_rpc_error(-4, "Maximum transaction weight is less than transaction weight without inputs", self.nodes[0].walletcreatefundedpsbt, [], dest_arg_large, 0, {"max_tx_weight": min_tx_weight}) + assert_raises_rpc_error(-4, "Maximum transaction weight is less than transaction weight without inputs", self.nodes[0].walletcreatefundedpsbt, [], dest_arg_large, 0, {"max_tx_weight": large_tx_weight_without_inputs}) + + # Test for max_tx_weight just enough to include inputs but not change output + assert_raises_rpc_error(-4, "Maximum transaction weight is too low, can not accommodate change output", self.nodes[0].walletcreatefundedpsbt, [], dest_arg_large, 0, {"max_tx_weight": (large_tx_vsize_without_inputs + 1) * WITNESS_SCALE_FACTOR}) + self.log.info("Test that a funded PSBT is always faithful to max_tx_weight option") + large_tx_vsize_with_change = large_tx_vsize_without_inputs + p2wpkh_output_vsize + # It's enough but won't accommodate selected input size + assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight", self.nodes[0].walletcreatefundedpsbt, [], dest_arg_large, 0, {"max_tx_weight": (large_tx_vsize_with_change) * WITNESS_SCALE_FACTOR}) + + max_tx_weight_sufficient = 1000 # 1k vbytes is enough + psbt = self.nodes[0].walletcreatefundedpsbt(outputs=dest_arg,locktime=0, options={"max_tx_weight": max_tx_weight_sufficient})["psbt"] + weight = self.nodes[0].decodepsbt(psbt)["tx"]["weight"] + # ensure the transaction's weight is below the specified max_tx_weight. + assert_greater_than_or_equal(max_tx_weight_sufficient, weight) + # If inputs are specified, do not automatically add more: utxo1 = self.nodes[0].listunspent()[0] assert_raises_rpc_error(-4, "The preselected coins total amount does not cover the transaction target. " @@ -589,6 +656,7 @@ class PSBTTest(BitcoinTestFramework): if self.options.descriptors: self.test_utxo_conversion() + self.test_psbt_incomplete_after_invalid_modification() self.test_input_confs_control() @@ -700,11 +768,9 @@ class PSBTTest(BitcoinTestFramework): assert_equal(analysis['next'], 'creator') assert_equal(analysis['error'], 'PSBT is not valid. Output amount invalid') - analysis = self.nodes[0].analyzepsbt('cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==') - assert_equal(analysis['next'], 'creator') - assert_equal(analysis['error'], 'PSBT is not valid. Input 0 specifies invalid prevout') + assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].analyzepsbt, "cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==") - assert_raises_rpc_error(-25, 'Inputs missing or spent', self.nodes[0].walletprocesspsbt, 'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==') + assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].walletprocesspsbt, "cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==") self.log.info("Test that we can fund psbts with external inputs specified") @@ -987,4 +1053,4 @@ class PSBTTest(BitcoinTestFramework): if __name__ == '__main__': - PSBTTest().main() + PSBTTest(__file__).main() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index f974a05f7b..18b1fc1896 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -430,13 +430,13 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(testres['allowed'], True) self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate='0.20000000') - self.log.info("Test sendrawtransaction/testmempoolaccept with tx already in the chain") + self.log.info("Test sendrawtransaction/testmempoolaccept with tx outputs already in the utxo set") self.generate(self.nodes[2], 1) for node in self.nodes: testres = node.testmempoolaccept([tx['hex']])[0] assert_equal(testres['allowed'], False) assert_equal(testres['reject-reason'], 'txn-already-known') - assert_raises_rpc_error(-27, 'Transaction already in block chain', node.sendrawtransaction, tx['hex']) + assert_raises_rpc_error(-27, 'Transaction outputs already in utxo set', node.sendrawtransaction, tx['hex']) def decoderawtransaction_tests(self): self.log.info("Test decoderawtransaction") @@ -612,4 +612,4 @@ class RawTransactionsTest(BitcoinTestFramework): if __name__ == '__main__': - RawTransactionsTest().main() + RawTransactionsTest(__file__).main() diff --git a/test/functional/rpc_scanblocks.py b/test/functional/rpc_scanblocks.py index 8b4aebc77a..d05ba09ba5 100755 --- a/test/functional/rpc_scanblocks.py +++ b/test/functional/rpc_scanblocks.py @@ -136,4 +136,4 @@ class ScanblocksTest(BitcoinTestFramework): if __name__ == '__main__': - ScanblocksTest().main() + ScanblocksTest(__file__).main() diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index 9f77f209ef..e53e2fa910 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -120,7 +120,15 @@ class ScantxoutsetTest(BitcoinTestFramework): assert_equal(self.nodes[0].scantxoutset("status"), None) assert_equal(self.nodes[0].scantxoutset("abort"), False) - # check that first arg is needed + # Check that the blockhash and confirmations fields are correct + self.generate(self.nodes[0], 2) + unspent = self.nodes[0].scantxoutset("start", ["addr(mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq)"])["unspents"][0] + blockhash = self.nodes[0].getblockhash(info["height"]) + assert_equal(unspent["height"], info["height"]) + assert_equal(unspent["blockhash"], blockhash) + assert_equal(unspent["confirmations"], 3) + + # Check that first arg is needed assert_raises_rpc_error(-1, "scantxoutset \"action\" ( [scanobjects,...] )", self.nodes[0].scantxoutset) # Check that second arg is needed for start @@ -131,4 +139,4 @@ class ScantxoutsetTest(BitcoinTestFramework): if __name__ == "__main__": - ScantxoutsetTest().main() + ScantxoutsetTest(__file__).main() diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py index ba86b278bd..c4e5ebccca 100755 --- a/test/functional/rpc_setban.py +++ b/test/functional/rpc_setban.py @@ -75,4 +75,4 @@ class SetBanTests(BitcoinTestFramework): assert_equal(banned['ban_duration'], 1234) if __name__ == '__main__': - SetBanTests().main() + SetBanTests(__file__).main() diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py index 488682e959..7dd16ea8fe 100755 --- a/test/functional/rpc_signer.py +++ b/test/functional/rpc_signer.py @@ -77,4 +77,4 @@ class RPCSignerTest(BitcoinTestFramework): assert_equal({'fingerprint': '00000001', 'name': 'trezor_t'} in self.nodes[1].enumeratesigners()['signers'], True) if __name__ == '__main__': - RPCSignerTest().main() + RPCSignerTest(__file__).main() diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py index c5df22157d..8e86698781 100755 --- a/test/functional/rpc_signmessagewithprivkey.py +++ b/test/functional/rpc_signmessagewithprivkey.py @@ -60,4 +60,4 @@ class SignMessagesWithPrivTest(BitcoinTestFramework): if __name__ == '__main__': - SignMessagesWithPrivTest().main() + SignMessagesWithPrivTest(__file__).main() diff --git a/test/functional/rpc_signrawtransactionwithkey.py b/test/functional/rpc_signrawtransactionwithkey.py index f4fec13495..be96742aa8 100755 --- a/test/functional/rpc_signrawtransactionwithkey.py +++ b/test/functional/rpc_signrawtransactionwithkey.py @@ -9,6 +9,7 @@ from test_framework.blocktools import ( ) from test_framework.address import ( address_to_scriptpubkey, + p2a, script_to_p2sh, ) from test_framework.test_framework import BitcoinTestFramework @@ -100,6 +101,18 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework): for tx_type in ['P2PKH', 'P2PK']: # these tests are order-independent self.verify_txn_with_witness_script(tx_type) + def keyless_signing_test(self): + self.log.info("Test that keyless 'signing' of pay-to-anchor input succeeds") + funding_txid = self.send_to_address(p2a(), 49.999) + spending_tx = self.nodes[0].createrawtransaction( + [{"txid": funding_txid, "vout": 0}], + [{getnewdestination()[2]: Decimal("49.998")}]) + spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [], []) + self.assert_signing_completed_successfully(spending_tx_signed) + assert self.nodes[0].testmempoolaccept([spending_tx_signed["hex"]])[0]["allowed"] + # 'signing' a P2A prevout is a no-op, so signed and unsigned txs shouldn't differ + assert_equal(spending_tx, spending_tx_signed["hex"]) + def verify_txn_with_witness_script(self, tx_type): self.log.info("Test with a {} script as the witnessScript".format(tx_type)) embedded_privkey, embedded_pubkey = generate_keypair(wif=True) @@ -138,9 +151,10 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework): def run_test(self): self.successful_signing_test() self.witness_script_test() + self.keyless_signing_test() self.invalid_sighashtype_test() self.invalid_private_key_and_tx() if __name__ == '__main__': - SignRawTransactionWithKeyTest().main() + SignRawTransactionWithKeyTest(__file__).main() diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 60b7ce8d20..387132b680 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -104,4 +104,4 @@ class MerkleBlockTest(BitcoinTestFramework): # verify that the proofs are invalid if __name__ == '__main__': - MerkleBlockTest().main() + MerkleBlockTest(__file__).main() diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py index f8df59d02a..fdf459953c 100755 --- a/test/functional/rpc_uptime.py +++ b/test/functional/rpc_uptime.py @@ -32,4 +32,4 @@ class UptimeTest(BitcoinTestFramework): if __name__ == '__main__': - UptimeTest().main() + UptimeTest(__file__).main() diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py index 153493fbab..44187ce790 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -156,4 +156,4 @@ class HTTPBasicsTest(BitcoinTestFramework): if __name__ == '__main__': - HTTPBasicsTest().main() + HTTPBasicsTest(__file__).main() diff --git a/test/functional/rpc_validateaddress.py b/test/functional/rpc_validateaddress.py index d87ba098c3..bf094a7df8 100755 --- a/test/functional/rpc_validateaddress.py +++ b/test/functional/rpc_validateaddress.py @@ -166,6 +166,11 @@ VALID_DATA = [ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", ), + # PayToAnchor(P2A) + ( + "bc1pfeessrawgf", + "51024e73", + ), ] @@ -200,4 +205,4 @@ class ValidateAddressMainTest(BitcoinTestFramework): if __name__ == "__main__": - ValidateAddressMainTest().main() + ValidateAddressMainTest(__file__).main() diff --git a/test/functional/rpc_whitelist.py b/test/functional/rpc_whitelist.py index fb404fb479..5f74fe8274 100755 --- a/test/functional/rpc_whitelist.py +++ b/test/functional/rpc_whitelist.py @@ -93,4 +93,4 @@ class RPCWhitelistTest(BitcoinTestFramework): assert_equal(200, rpccall(self.nodes[0], self.strange_users[4], "getblockcount").status) if __name__ == "__main__": - RPCWhitelistTest().main() + RPCWhitelistTest(__file__).main() diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md index 4cd62c4ef3..d79c4a0ab6 100644 --- a/test/functional/test-shell.md +++ b/test/functional/test-shell.md @@ -169,7 +169,7 @@ can be called after the TestShell is shut down. | Test parameter key | Default Value | Description | |---|---|---| -| `bind_to_localhost_only` | `True` | Binds bitcoind RPC services to `127.0.0.1` if set to `True`.| +| `bind_to_localhost_only` | `True` | Binds bitcoind P2P services to `127.0.0.1` if set to `True`.| | `cachedir` | `"/path/to/bitcoin/test/cache"` | Sets the bitcoind datadir directory. | | `chain` | `"regtest"` | Sets the chain-type for the underlying test bitcoind processes. | | `configfile` | `"/path/to/bitcoin/test/config.ini"` | Sets the location of the test framework config file. | diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index bcb38b21cd..2c754e35aa 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -53,13 +53,14 @@ def create_deterministic_address_bcrt1_p2tr_op_true(explicit_internal_key=None): can be spent with a witness stack of OP_TRUE and the control block with internal public key (script-path spending). - Returns a tuple with the generated address and the internal key. + Returns a tuple with the generated address and the TaprootInfo object. """ internal_key = explicit_internal_key or (1).to_bytes(32, 'big') - address = output_key_to_p2tr(taproot_construct(internal_key, [(None, CScript([OP_TRUE]))]).output_pubkey) + taproot_info = taproot_construct(internal_key, [("only-path", CScript([OP_TRUE]))]) + address = output_key_to_p2tr(taproot_info.output_pubkey) if explicit_internal_key is None: assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka') - return (address, internal_key) + return (address, taproot_info) def byte_to_base58(b, version): @@ -154,6 +155,9 @@ def output_key_to_p2tr(key, main=False): assert len(key) == 32 return program_to_witness(1, key, main) +def p2a(main=False): + return program_to_witness(1, "4e73", main) + def check_key(key): if (type(key) is str): key = bytes.fromhex(key) # Assuming this is hex string diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index f0dc866f69..5c2fa28a31 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -48,6 +48,7 @@ from .util import assert_equal MAX_BLOCK_SIGOPS = 20000 MAX_BLOCK_SIGOPS_WEIGHT = MAX_BLOCK_SIGOPS * WITNESS_SCALE_FACTOR +MAX_STANDARD_TX_WEIGHT = 400000 # Genesis block time (regtest) TIME_GENESIS_BLOCK = 1296688602 @@ -153,16 +154,18 @@ def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_scr coinbase.calc_sha256() return coinbase -def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=CScript()): +def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, output_script=None): """Return one-input, one-output transaction object spending the prevtx's n-th output with the given amount. Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output. """ + if output_script is None: + output_script = CScript() tx = CTransaction() assert n < len(prevtx.vout) tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, SEQUENCE_FINAL)) - tx.vout.append(CTxOut(amount, script_pub_key)) + tx.vout.append(CTxOut(amount, output_script)) tx.calc_sha256() return tx diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py index 06252f8996..939c7cbef6 100644 --- a/test/functional/test_framework/key.py +++ b/test/functional/test_framework/key.py @@ -14,6 +14,7 @@ import random import unittest from test_framework.crypto import secp256k1 +from test_framework.util import random_bitflip # Point with no known discrete log. H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0" @@ -292,11 +293,6 @@ def sign_schnorr(key, msg, aux=None, flip_p=False, flip_r=False): class TestFrameworkKey(unittest.TestCase): def test_ecdsa_and_schnorr(self): """Test the Python ECDSA and Schnorr implementations.""" - def random_bitflip(sig): - sig = list(sig) - sig[random.randrange(len(sig))] ^= (1 << (random.randrange(8))) - return bytes(sig) - byte_arrays = [generate_privkey() for _ in range(3)] + [v.to_bytes(32, 'big') for v in [0, ORDER - 1, ORDER, 2**256 - 1]] keys = {} for privkey_bytes in byte_arrays: # build array of key/pubkey pairs diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 005f7546a8..1f566a1348 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -1294,8 +1294,11 @@ class msg_tx: __slots__ = ("tx",) msgtype = b"tx" - def __init__(self, tx=CTransaction()): - self.tx = tx + def __init__(self, tx=None): + if tx is None: + self.tx = CTransaction() + else: + self.tx = tx def deserialize(self, f): self.tx.deserialize(f) diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 4b846df94a..4f1265eb54 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -223,6 +223,7 @@ class P2PConnection(asyncio.Protocol): # send the initial handshake immediately if self.supports_v2_p2p and self.v2_state.initiating and not self.v2_state.tried_v2_handshake: send_handshake_bytes = self.v2_state.initiate_v2_handshake() + logger.debug(f"sending {len(self.v2_state.sent_garbage)} bytes of garbage data") self.send_raw_message(send_handshake_bytes) # for v1 outbound connections, send version message immediately after opening # (for v2 outbound connections, send it after the initial v2 handshake) @@ -262,6 +263,7 @@ class P2PConnection(asyncio.Protocol): self.v2_state = None return elif send_handshake_bytes: + logger.debug(f"sending {len(self.v2_state.sent_garbage)} bytes of garbage data") self.send_raw_message(send_handshake_bytes) elif send_handshake_bytes == b"": return # only after send_handshake_bytes are sent can `complete_handshake()` be done diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 97d62f957b..d510cf9b1c 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -810,7 +810,7 @@ def BIP341_sha_sequences(txTo): def BIP341_sha_outputs(txTo): return sha256(b"".join(o.serialize() for o in txTo.vout)) -def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT): +def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index=0, *, scriptpath=False, leaf_script=None, codeseparator_pos=-1, annex=None, leaf_ver=LEAF_VERSION_TAPSCRIPT): assert (len(txTo.vin) == len(spent_utxos)) assert (input_index < len(txTo.vin)) out_type = SIGHASH_ALL if hash_type == 0 else hash_type & 3 @@ -829,7 +829,7 @@ def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index = 0, scriptpat spend_type = 0 if annex is not None: spend_type |= 1 - if (scriptpath): + if scriptpath: spend_type |= 2 ss += bytes([spend_type]) if in_type == SIGHASH_ANYONECANPAY: @@ -846,11 +846,11 @@ def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index = 0, scriptpat ss += sha256(txTo.vout[input_index].serialize()) else: ss += bytes(0 for _ in range(32)) - if (scriptpath): - ss += TaggedHash("TapLeaf", bytes([leaf_ver]) + ser_string(script)) + if scriptpath: + ss += TaggedHash("TapLeaf", bytes([leaf_ver]) + ser_string(leaf_script)) ss += bytes([0]) ss += codeseparator_pos.to_bytes(4, "little", signed=True) - assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * 49 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37 + assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * 49 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37 return ss def TaprootSignatureHash(*args, **kwargs): diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py index 855f3b8cf5..938183ece4 100755 --- a/test/functional/test_framework/script_util.py +++ b/test/functional/test_framework/script_util.py @@ -8,6 +8,7 @@ import unittest from test_framework.script import ( CScript, OP_0, + OP_1, OP_15, OP_16, OP_CHECKMULTISIG, @@ -42,6 +43,8 @@ assert MIN_PADDING == 5 DUMMY_MIN_OP_RETURN_SCRIPT = CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 1))) assert len(DUMMY_MIN_OP_RETURN_SCRIPT) == MIN_PADDING +PAY_TO_ANCHOR = CScript([OP_1, bytes.fromhex("4e73")]) + def key_to_p2pk_script(key): key = check_key(key) return CScript([key, OP_CHECKSIG]) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 9e44a11143..49212eb019 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -92,7 +92,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): This class also contains various public and private helper methods.""" - def __init__(self) -> None: + def __init__(self, test_file) -> None: """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" self.chain: str = 'regtest' self.setup_clean_chain: bool = False @@ -103,7 +103,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond self.supports_cli = True self.bind_to_localhost_only = True - self.parse_args() + self.parse_args(test_file) self.default_wallet_name = "default_wallet" if self.options.descriptors else "" self.wallet_data_filename = "wallet.dat" # Optional list of wallet names that can be set in set_test_params to @@ -155,14 +155,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): exit_code = self.shutdown() sys.exit(exit_code) - def parse_args(self): + def parse_args(self, test_file): previous_releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases" parser = argparse.ArgumentParser(usage="%(prog)s [options]") parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true", help="Don't stop bitcoinds after the test execution") - parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../cache"), + parser.add_argument("--cachedir", dest="cachedir", default=os.path.abspath(os.path.dirname(test_file) + "/../cache"), help="Directory for caching pregenerated datadirs (default: %(default)s)") parser.add_argument("--tmpdir", dest="tmpdir", help="Root directory for datadirs (must not exist)") parser.add_argument("-l", "--loglevel", dest="loglevel", default="INFO", @@ -177,7 +177,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): parser.add_argument("--coveragedir", dest="coveragedir", help="Write tested RPC commands into this directory") parser.add_argument("--configfile", dest="configfile", - default=os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../config.ini"), + default=os.path.abspath(os.path.dirname(test_file) + "/../config.ini"), help="Location of the test framework config file (default: %(default)s)") parser.add_argument("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true", help="Attach a python debugger if test fails") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 0ac0af27d5..b73566b0e9 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -39,6 +39,7 @@ from .util import ( rpc_url, wait_until_helper_internal, p2p_port, + tor_port, ) BITCOIND_PROC_WAIT_TIMEOUT = 60 @@ -88,8 +89,11 @@ class TestNode(): self.coverage_dir = coverage_dir self.cwd = cwd self.descriptors = descriptors + self.has_explicit_bind = False if extra_conf is not None: append_config(self.datadir_path, extra_conf) + # Remember if there is bind=... in the config file. + self.has_explicit_bind = any(e.startswith("bind=") for e in extra_conf) # Most callers will just need to add extra args to the standard list below. # For those callers that need more flexibility, they can just set the args property directly. # Note that common args are set in the config file (see initialize_datadir) @@ -210,6 +214,17 @@ class TestNode(): if extra_args is None: extra_args = self.extra_args + # If listening and no -bind is given, then bitcoind would bind P2P ports on + # 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is + # a unique port chosen by the test framework and configured as port=P in + # bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to + # 127.0.0.1:tor_port(). + will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args) + has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args) + if will_listen and not has_explicit_bind: + extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}") + extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion") + self.use_v2transport = "-v2transport=1" in extra_args or (self.default_to_v2 and "-v2transport=0" not in extra_args) # Add a new stdout and stderr file each time bitcoind is started @@ -666,7 +681,7 @@ class TestNode(): assert_msg += "with expected error " + expected_msg self._raise_assertion_error(assert_msg) - def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, send_version=True, supports_v2_p2p=None, wait_for_v2_handshake=True, **kwargs): + def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, send_version=True, supports_v2_p2p=None, wait_for_v2_handshake=True, expect_success=True, **kwargs): """Add an inbound p2p connection to the node. This method adds the p2p connection to the self.p2ps list and also @@ -686,7 +701,6 @@ class TestNode(): if supports_v2_p2p is None: supports_v2_p2p = self.use_v2transport - p2p_conn.p2p_connected_to_node = True if self.use_v2transport: kwargs['services'] = kwargs.get('services', P2P_SERVICES) | NODE_P2P_V2 @@ -694,6 +708,8 @@ class TestNode(): p2p_conn.peer_connect(**kwargs, send_version=send_version, net=self.chain, timeout_factor=self.timeout_factor, supports_v2_p2p=supports_v2_p2p)() self.p2ps.append(p2p_conn) + if not expect_success: + return p2p_conn p2p_conn.wait_until(lambda: p2p_conn.is_connected, check_connected=False) if supports_v2_p2p and wait_for_v2_handshake: p2p_conn.wait_until(lambda: p2p_conn.v2_state.tried_v2_handshake) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index c5b69a3954..c3bc861cf6 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -14,6 +14,7 @@ import logging import os import pathlib import platform +import random import re import time @@ -247,6 +248,12 @@ def ceildiv(a, b): return -(-a // b) +def random_bitflip(data): + data = list(data) + data[random.randrange(len(data))] ^= (1 << (random.randrange(8))) + return bytes(data) + + def get_fee(tx_size, feerate_btc_kvb): """Calculate the fee in BTC given a feerate is BTC/kvB. Reflects CFeeRate::GetFee""" feerate_sat_kvb = int(feerate_btc_kvb * Decimal(1e8)) # Fee in sat/kvb as an int to avoid float precision errors @@ -304,14 +311,21 @@ def sha256sum_file(filename): return h.digest() +def util_xor(data, key, *, offset): + data = bytearray(data) + for i in range(len(data)): + data[i] ^= key[(i + offset) % len(key)] + return bytes(data) + + # RPC/P2P connection constants and functions ############################################ # The maximum number of nodes a single test can spawn MAX_NODES = 12 -# Don't assign rpc or p2p ports lower than this +# Don't assign p2p, rpc or tor ports lower than this PORT_MIN = int(os.getenv('TEST_RUNNER_PORT_MIN', default=11000)) -# The number of ports to "reserve" for p2p and rpc, each +# The number of ports to "reserve" for p2p, rpc and tor, each PORT_RANGE = 5000 @@ -351,7 +365,11 @@ def p2p_port(n): def rpc_port(n): - return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) + return p2p_port(n) + PORT_RANGE + + +def tor_port(n): + return p2p_port(n) + PORT_RANGE * 2 def rpc_url(datadir, i, chain, rpchost): @@ -497,6 +515,12 @@ def check_node_connections(*, node, num_in, num_out): assert_equal(info["connections_out"], num_out) +def read_xor_key(*, node): + with open(node.blocks_path / "xor.dat", "rb") as xor_f: + NUM_XOR_BYTES = 8 # From InitBlocksdirXorKey::xor_key.size() + return xor_f.read(NUM_XOR_BYTES) + + # Transaction/Block functions ############################# diff --git a/test/functional/test_framework/v2_p2p.py b/test/functional/test_framework/v2_p2p.py index 8f79623bd8..87600c36de 100644 --- a/test/functional/test_framework/v2_p2p.py +++ b/test/functional/test_framework/v2_p2p.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Class for v2 P2P protocol (see BIP 324)""" -import logging import random from .crypto.bip324_cipher import FSChaCha20Poly1305 @@ -14,14 +13,12 @@ from .crypto.hkdf import hkdf_sha256 from .key import TaggedHash from .messages import MAGIC_BYTES -logger = logging.getLogger("TestFramework.v2_p2p") CHACHA20POLY1305_EXPANSION = 16 HEADER_LEN = 1 IGNORE_BIT_POS = 7 LENGTH_FIELD_LEN = 3 MAX_GARBAGE_LEN = 4095 -TRANSPORT_VERSION = b'' SHORTID = { 1: b"addr", @@ -95,6 +92,7 @@ class EncryptedP2PState: # has been decrypted. set to -1 if decryption hasn't been done yet. self.contents_len = -1 self.found_garbage_terminator = False + self.transport_version = b'' @staticmethod def v2_ecdh(priv, ellswift_theirs, ellswift_ours, initiating): @@ -111,12 +109,12 @@ class EncryptedP2PState: # Responding, place their public key encoding first. return TaggedHash("bip324_ellswift_xonly_ecdh", ellswift_theirs + ellswift_ours + ecdh_point_x32) - def generate_keypair_and_garbage(self): + def generate_keypair_and_garbage(self, garbage_len=None): """Generates ellswift keypair and 4095 bytes garbage at max""" self.privkey_ours, self.ellswift_ours = ellswift_create() - garbage_len = random.randrange(MAX_GARBAGE_LEN + 1) + if garbage_len is None: + garbage_len = random.randrange(MAX_GARBAGE_LEN + 1) self.sent_garbage = random.randbytes(garbage_len) - logger.debug(f"sending {garbage_len} bytes of garbage data") return self.ellswift_ours + self.sent_garbage def initiate_v2_handshake(self): @@ -172,7 +170,7 @@ class EncryptedP2PState: msg_to_send += self.v2_enc_packet(decoy_content_len * b'\x00', aad=aad, ignore=True) aad = b'' # Send version packet. - msg_to_send += self.v2_enc_packet(TRANSPORT_VERSION, aad=aad) + msg_to_send += self.v2_enc_packet(self.transport_version, aad=aad) return 64 - len(self.received_prefix), msg_to_send def authenticate_handshake(self, response): diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index cb0d291361..f3713f297e 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -39,7 +39,6 @@ from test_framework.messages import ( ) from test_framework.script import ( CScript, - LEAF_VERSION_TAPSCRIPT, OP_1, OP_NOP, OP_RETURN, @@ -106,8 +105,8 @@ class MiniWallet: pub_key = self._priv_key.get_pubkey() self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes()) elif mode == MiniWalletMode.ADDRESS_OP_TRUE: - internal_key = None if tag_name is None else hash256(tag_name.encode()) - self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true(internal_key) + internal_key = None if tag_name is None else compute_xonly_pubkey(hash256(tag_name.encode()))[0] + self._address, self._taproot_info = create_deterministic_address_bcrt1_p2tr_op_true(internal_key) self._scriptPubKey = address_to_scriptpubkey(self._address) # When the pre-mined test framework chain is used, it contains coinbase @@ -195,7 +194,12 @@ class MiniWallet: 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] + assert_equal(len(self._taproot_info.leaves), 1) + leaf_info = list(self._taproot_info.leaves.values())[0] + i.scriptWitness.stack = [ + leaf_info.script, + bytes([leaf_info.version | self._taproot_info.negflag]) + self._taproot_info.internal_pubkey, + ] else: assert False diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index a55e45fa15..b85bf1c668 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -264,7 +264,7 @@ BASE_SCRIPTS = [ 'p2p_invalid_tx.py --v2transport', 'p2p_v2_transport.py', 'p2p_v2_encrypted.py', - 'p2p_v2_earlykeyresponse.py', + 'p2p_v2_misbehaving.py', 'example_test.py', 'mempool_truc.py', 'wallet_txn_doublespend.py --legacy-wallet', @@ -284,6 +284,7 @@ BASE_SCRIPTS = [ 'mempool_package_limits.py', 'mempool_package_rbf.py', 'feature_versionbits_warning.py', + 'feature_blocksxor.py', 'rpc_preciousblock.py', 'wallet_importprunedfunds.py --legacy-wallet', 'wallet_importprunedfunds.py --descriptors', diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index 1ad2a579bf..bdefb92ae6 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -62,4 +62,4 @@ class SignetMinerTest(BitcoinTestFramework): if __name__ == "__main__": - SignetMinerTest().main() + SignetMinerTest(__file__).main() diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index dcf74f6075..784a769882 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -563,4 +563,4 @@ class ToolWalletTest(BitcoinTestFramework): self.test_dump_very_large_records() if __name__ == '__main__': - ToolWalletTest().main() + ToolWalletTest(__file__).main() diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index dda48aae1b..ce0f4d099b 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -241,4 +241,4 @@ class AbandonConflictTest(BitcoinTestFramework): assert_equal(newbalance, balance - Decimal("20")) if __name__ == '__main__': - AbandonConflictTest().main() + AbandonConflictTest(__file__).main() diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index 6b27b32dea..e326d3e89e 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -387,4 +387,4 @@ class AddressTypeTest(BitcoinTestFramework): assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getrawchangeaddress, "bech32m") if __name__ == '__main__': - AddressTypeTest().main() + AddressTypeTest(__file__).main() diff --git a/test/functional/wallet_assumeutxo.py b/test/functional/wallet_assumeutxo.py index 30396da015..0bce2f137c 100755 --- a/test/functional/wallet_assumeutxo.py +++ b/test/functional/wallet_assumeutxo.py @@ -164,4 +164,4 @@ class AssumeutxoTest(BitcoinTestFramework): if __name__ == '__main__': - AssumeutxoTest().main() + AssumeutxoTest(__file__).main() diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py index 66fbf780e5..146b3df3f4 100755 --- a/test/functional/wallet_avoid_mixing_output_types.py +++ b/test/functional/wallet_avoid_mixing_output_types.py @@ -177,4 +177,4 @@ class AddressInputTypeGrouping(BitcoinTestFramework): if __name__ == '__main__': - AddressInputTypeGrouping().main() + AddressInputTypeGrouping(__file__).main() diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py index 4983bfda7f..bba79d0a25 100755 --- a/test/functional/wallet_avoidreuse.py +++ b/test/functional/wallet_avoidreuse.py @@ -381,4 +381,4 @@ class AvoidReuseTest(BitcoinTestFramework): if __name__ == '__main__': - AvoidReuseTest().main() + AvoidReuseTest(__file__).main() diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index d03b08bcc4..a639c34377 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -244,4 +244,4 @@ class WalletBackupTest(BitcoinTestFramework): if __name__ == '__main__': - WalletBackupTest().main() + WalletBackupTest(__file__).main() diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index ab008a40cd..e71283b928 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -400,4 +400,4 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): assert_equal(info, addr_info) if __name__ == '__main__': - BackwardsCompatibilityTest().main() + BackwardsCompatibilityTest(__file__).main() diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 2c85773bf3..9da53402a4 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -339,4 +339,4 @@ class WalletTest(BitcoinTestFramework): assert_equal(tx_info['lastprocessedblock']['hash'], prev_hash) if __name__ == '__main__': - WalletTest().main() + WalletTest(__file__).main() diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 1b2b8ec1f3..c968e4333a 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -818,4 +818,4 @@ class WalletTest(BitcoinTestFramework): if __name__ == '__main__': - WalletTest().main() + WalletTest(__file__).main() diff --git a/test/functional/wallet_blank.py b/test/functional/wallet_blank.py index e646d27005..76f9cb05ee 100755 --- a/test/functional/wallet_blank.py +++ b/test/functional/wallet_blank.py @@ -160,4 +160,4 @@ class WalletBlankTest(BitcoinTestFramework): if __name__ == '__main__': - WalletBlankTest().main() + WalletBlankTest(__file__).main() diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 6d45adc823..061e9f2caa 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -848,10 +848,10 @@ def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, # less than (original fee + incrementalrelayfee) assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.8}) - # You can fee bump as long as the new fee set from fee_rate is atleast (original fee + incrementalrelayfee) + # You can fee bump as long as the new fee set from fee_rate is at least (original fee + incrementalrelayfee) rbf_node.bumpfee(tx["txid"], {"fee_rate": 3}) self.clear_mempool() if __name__ == "__main__": - BumpFeeTest().main() + BumpFeeTest(__file__).main() diff --git a/test/functional/wallet_change_address.py b/test/functional/wallet_change_address.py index f8bfe9eebf..07bab82697 100755 --- a/test/functional/wallet_change_address.py +++ b/test/functional/wallet_change_address.py @@ -105,4 +105,4 @@ class WalletChangeAddressTest(BitcoinTestFramework): self.assert_change_pos(w1, tx, 0) if __name__ == '__main__': - WalletChangeAddressTest().main() + WalletChangeAddressTest(__file__).main() diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py index c2cb0bf3b0..f09ed4913a 100755 --- a/test/functional/wallet_coinbase_category.py +++ b/test/functional/wallet_coinbase_category.py @@ -60,4 +60,4 @@ class CoinbaseCategoryTest(BitcoinTestFramework): self.assert_category("orphan", address, txid, 100) if __name__ == '__main__': - CoinbaseCategoryTest().main() + CoinbaseCategoryTest(__file__).main() diff --git a/test/functional/wallet_conflicts.py b/test/functional/wallet_conflicts.py index 25a95aa954..7a950ffae6 100755 --- a/test/functional/wallet_conflicts.py +++ b/test/functional/wallet_conflicts.py @@ -423,4 +423,4 @@ class TxConflicts(BitcoinTestFramework): carol.unloadwallet() if __name__ == '__main__': - TxConflicts().main() + TxConflicts(__file__).main() diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py index 41ddb2bc69..6deb262c9a 100755 --- a/test/functional/wallet_create_tx.py +++ b/test/functional/wallet_create_tx.py @@ -129,4 +129,4 @@ class CreateTxWalletTest(BitcoinTestFramework): if __name__ == '__main__': - CreateTxWalletTest().main() + CreateTxWalletTest(__file__).main() diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 8e07021e03..0232af1658 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -190,4 +190,4 @@ class CreateWalletTest(BitcoinTestFramework): if __name__ == '__main__': - CreateWalletTest().main() + CreateWalletTest(__file__).main() diff --git a/test/functional/wallet_createwalletdescriptor.py b/test/functional/wallet_createwalletdescriptor.py index 18e1703da3..e8cd914769 100755 --- a/test/functional/wallet_createwalletdescriptor.py +++ b/test/functional/wallet_createwalletdescriptor.py @@ -120,4 +120,4 @@ class WalletCreateDescriptorTest(BitcoinTestFramework): if __name__ == '__main__': - WalletCreateDescriptorTest().main() + WalletCreateDescriptorTest(__file__).main() diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py index 4c5d7192ae..97db84c3e4 100755 --- a/test/functional/wallet_crosschain.py +++ b/test/functional/wallet_crosschain.py @@ -11,7 +11,7 @@ class WalletCrossChain(BitcoinTestFramework): self.add_wallet_options(parser) def set_test_params(self): - self.num_nodes = 2 + self.num_nodes = 3 self.setup_clean_chain = True def skip_test_if_missing_module(self): @@ -24,6 +24,12 @@ class WalletCrossChain(BitcoinTestFramework): self.nodes[1].chain = 'testnet3' self.nodes[1].extra_args = ['-maxconnections=0', '-prune=550'] # disable testnet sync self.nodes[1].replace_in_config([('regtest=', 'testnet='), ('[regtest]', '[test]')]) + + # Switch node 2 to testnet4 before starting it. + self.nodes[2].chain = 'testnet4' + self.nodes[2].extra_args = ['-maxconnections=0', '-prune=550'] # disable testnet4 sync + self.nodes[2].replace_in_config([('regtest=', 'testnet4='), ('[regtest]', '[testnet4]')]) + self.start_nodes() def run_test(self): @@ -39,19 +45,40 @@ class WalletCrossChain(BitcoinTestFramework): self.nodes[1].createwallet(node1_wallet) self.nodes[1].backupwallet(node1_wallet_backup) self.nodes[1].unloadwallet(node1_wallet) + node2_wallet = self.nodes[2].datadir_path / 'node2_wallet' + node2_wallet_backup = self.nodes[0].datadir_path / 'node2_wallet.bak' + self.nodes[2].createwallet(node2_wallet) + self.nodes[2].backupwallet(node2_wallet_backup) + self.nodes[2].unloadwallet(node2_wallet) 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[0].loadwallet, node2_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[2].loadwallet, node0_wallet) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].loadwallet, node2_wallet) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].loadwallet, node1_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[0].restorewallet, 'w', node2_wallet_backup) assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].restorewallet, 'w', node0_wallet_backup) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node2_wallet_backup) + assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].restorewallet, 'w', node1_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[0].loadwallet, node2_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[2].loadwallet, node0_wallet) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].loadwallet, node2_wallet) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].loadwallet, node1_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[0].restorewallet, 'w', node2_wallet_backup) assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].restorewallet, 'w', node0_wallet_backup) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node2_wallet_backup) + assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].restorewallet, 'w', node1_wallet_backup) if not self.options.descriptors: self.log.info("Override cross-chain wallet load protection") @@ -62,4 +89,4 @@ class WalletCrossChain(BitcoinTestFramework): if __name__ == '__main__': - WalletCrossChain().main() + WalletCrossChain(__file__).main() diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index cbd3898f92..5e0ee97892 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -282,4 +282,4 @@ class WalletDescriptorTest(BitcoinTestFramework): if __name__ == '__main__': - WalletDescriptorTest().main () + WalletDescriptorTest(__file__).main() diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py index 9c73f7dead..da6e5d408f 100755 --- a/test/functional/wallet_disable.py +++ b/test/functional/wallet_disable.py @@ -28,4 +28,4 @@ class DisableWalletTest (BitcoinTestFramework): if __name__ == '__main__': - DisableWalletTest().main() + DisableWalletTest(__file__).main() diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index f50aae0c53..3a4f23a124 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -223,4 +223,4 @@ class WalletDumpTest(BitcoinTestFramework): w3.dumpwallet(self.nodes[0].datadir_path / "w3.dump") if __name__ == '__main__': - WalletDumpTest().main() + WalletDumpTest(__file__).main() diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index b30634010d..5a5fb3e5be 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -102,4 +102,4 @@ class WalletEncryptionTest(BitcoinTestFramework): if __name__ == '__main__': - WalletEncryptionTest().main() + WalletEncryptionTest(__file__).main() diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py index f0740b72fd..1849a602ab 100755 --- a/test/functional/wallet_fallbackfee.py +++ b/test/functional/wallet_fallbackfee.py @@ -32,4 +32,4 @@ class WalletRBFTest(BitcoinTestFramework): assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1})) if __name__ == '__main__': - WalletRBFTest().main() + WalletRBFTest(__file__).main() diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 1315bccafd..4ac441516e 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -99,4 +99,4 @@ class WalletFastRescanTest(BitcoinTestFramework): if __name__ == '__main__': - WalletFastRescanTest().main() + WalletFastRescanTest(__file__).main() diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index 3c1b2deb1d..827f27b431 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1322,15 +1322,15 @@ class RawTransactionsTest(BitcoinTestFramework): outputs = [] for _ in range(1472): outputs.append({wallet.getnewaddress(address_type="legacy"): 0.1}) - txid = self.nodes[0].send(outputs=outputs)["txid"] + txid = self.nodes[0].send(outputs=outputs, change_position=0)["txid"] self.generate(self.nodes[0], 1) # 272 WU per input (273 when high-s); picking 1471 inputs will exceed the max standard tx weight. rawtx = wallet.createrawtransaction([], [{wallet.getnewaddress(): 0.1 * 1471}]) - # 1) Try to fund transaction only using the preset inputs + # 1) Try to fund transaction only using the preset inputs (pick all 1472 inputs to cover the fee) input_weights = [] - for i in range(1471): + for i in range(1, 1473): # skip first output as it is the parent tx change output input_weights.append({"txid": txid, "vout": i, "weight": 273}) assert_raises_rpc_error(-4, "Transaction too large", wallet.fundrawtransaction, hexstring=rawtx, input_weights=input_weights) @@ -1523,4 +1523,4 @@ class RawTransactionsTest(BitcoinTestFramework): wallet.unloadwallet() if __name__ == '__main__': - RawTransactionsTest().main() + RawTransactionsTest(__file__).main() diff --git a/test/functional/wallet_gethdkeys.py b/test/functional/wallet_gethdkeys.py index f09b8c875a..b6edc29fe6 100755 --- a/test/functional/wallet_gethdkeys.py +++ b/test/functional/wallet_gethdkeys.py @@ -182,4 +182,4 @@ class WalletGetHDKeyTest(BitcoinTestFramework): if __name__ == '__main__': - WalletGetHDKeyTest().main() + WalletGetHDKeyTest(__file__).main() diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index 26477131cf..8d6c96c0e0 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -182,4 +182,4 @@ class WalletGroupTest(BitcoinTestFramework): if __name__ == '__main__': - WalletGroupTest().main() + WalletGroupTest(__file__).main() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 52161043ea..8f2a5fc78b 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -280,4 +280,4 @@ class WalletHDTest(BitcoinTestFramework): if __name__ == '__main__': - WalletHDTest().main() + WalletHDTest(__file__).main() diff --git a/test/functional/wallet_implicitsegwit.py b/test/functional/wallet_implicitsegwit.py index baa9bafb00..e5787c0304 100755 --- a/test/functional/wallet_implicitsegwit.py +++ b/test/functional/wallet_implicitsegwit.py @@ -65,4 +65,4 @@ class ImplicitSegwitTest(BitcoinTestFramework): check_implicit_transactions(implicit_keys, self.nodes[0]) if __name__ == '__main__': - ImplicitSegwitTest().main() + ImplicitSegwitTest(__file__).main() diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 2a9435b370..c5834c15d2 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -338,4 +338,4 @@ class ImportRescanTest(BitcoinTestFramework): if __name__ == "__main__": - ImportRescanTest().main() + ImportRescanTest(__file__).main() diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py index 0a1fc31ebc..9d01dfa5b7 100755 --- a/test/functional/wallet_import_with_label.py +++ b/test/functional/wallet_import_with_label.py @@ -125,4 +125,4 @@ class ImportWithLabel(BitcoinTestFramework): if __name__ == "__main__": - ImportWithLabel().main() + ImportWithLabel(__file__).main() diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py index f9d05a2fe4..6a69377c63 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -709,4 +709,4 @@ class ImportDescriptorsTest(BitcoinTestFramework): assert_equal(temp_wallet.getbalance(), encrypted_wallet.getbalance()) if __name__ == '__main__': - ImportDescriptorsTest().main() + ImportDescriptorsTest(__file__).main() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 31013f6323..42b470bb97 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -898,4 +898,4 @@ class ImportMultiTest(BitcoinTestFramework): if __name__ == '__main__': - ImportMultiTest().main() + ImportMultiTest(__file__).main() diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py index b3ae22cc44..467fddeb59 100755 --- a/test/functional/wallet_importprunedfunds.py +++ b/test/functional/wallet_importprunedfunds.py @@ -143,4 +143,4 @@ class ImportPrunedFundsTest(BitcoinTestFramework): if __name__ == '__main__': - ImportPrunedFundsTest().main() + ImportPrunedFundsTest(__file__).main() diff --git a/test/functional/wallet_inactive_hdchains.py b/test/functional/wallet_inactive_hdchains.py index c6d22ab90b..3b0c09c02b 100755 --- a/test/functional/wallet_inactive_hdchains.py +++ b/test/functional/wallet_inactive_hdchains.py @@ -146,4 +146,4 @@ class InactiveHDChainsTest(BitcoinTestFramework): if __name__ == '__main__': - InactiveHDChainsTest().main() + InactiveHDChainsTest(__file__).main() diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index 6ed8572347..d3b6ca1ed1 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -223,4 +223,4 @@ class KeyPoolTest(BitcoinTestFramework): assert_raises_rpc_error(-4, msg, w2.keypoolrefill, 100) if __name__ == '__main__': - KeyPoolTest().main() + KeyPoolTest(__file__).main() diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index e1bd85d8a9..25028d87bf 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -98,4 +98,4 @@ class KeypoolRestoreTest(BitcoinTestFramework): if __name__ == '__main__': - KeypoolRestoreTest().main() + KeypoolRestoreTest(__file__).main() diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py index f074339a2b..307e10ae34 100755 --- a/test/functional/wallet_labels.py +++ b/test/functional/wallet_labels.py @@ -256,4 +256,4 @@ def change_label(node, address, old_label, new_label): new_label.verify(node) if __name__ == '__main__': - WalletLabelsTest().main() + WalletLabelsTest(__file__).main() diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index 712b881322..c9d6c1f190 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -136,4 +136,4 @@ class ListDescriptorsTest(BitcoinTestFramework): if __name__ == '__main__': - ListDescriptorsTest().main() + ListDescriptorsTest(__file__).main() diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py index d0f1336a5e..522c7732fe 100755 --- a/test/functional/wallet_listreceivedby.py +++ b/test/functional/wallet_listreceivedby.py @@ -263,4 +263,4 @@ class ReceivedByTest(BitcoinTestFramework): if __name__ == '__main__': - ReceivedByTest().main() + ReceivedByTest(__file__).main() diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 15214539a9..d777212f96 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -505,4 +505,4 @@ class ListSinceBlockTest(BitcoinTestFramework): if __name__ == '__main__': - ListSinceBlockTest().main() + ListSinceBlockTest(__file__).main() diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py index c820eaa6f6..a9f2066dd1 100755 --- a/test/functional/wallet_listtransactions.py +++ b/test/functional/wallet_listtransactions.py @@ -330,4 +330,4 @@ class ListTransactionsTest(BitcoinTestFramework): if __name__ == '__main__': - ListTransactionsTest().main() + ListTransactionsTest(__file__).main() diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 890b6a5c1b..48ad8e4f2a 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -205,9 +205,13 @@ class WalletMigrationTest(BitcoinTestFramework): 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") + self.log.info("Test \"nothing to migrate\" when the user tries to migrate a loaded wallet with no legacy data") assert_raises_rpc_error(-4, "Error: This wallet is already a descriptor wallet", basic2.migratewallet) + self.log.info("Test \"nothing to migrate\" when the user tries to migrate an unloaded wallet with no legacy data") + basic2.unloadwallet() + assert_raises_rpc_error(-4, "Error: This wallet is already a descriptor wallet", self.nodes[0].migratewallet, "basic2") + def test_multisig(self): default = self.nodes[0].get_wallet_rpc(self.default_wallet_name) @@ -467,6 +471,12 @@ class WalletMigrationTest(BitcoinTestFramework): 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") + # Check the wallet is still active post-migration failure. + # If not, it will throw an exception and abort the test. + wallet.walletpassphrase("pass", 99999) + wallet.getnewaddress() + + # Verify we can properly migrate the encrypted wallet self.migrate_wallet(wallet, passphrase="pass") info = wallet.getwalletinfo() @@ -538,10 +548,15 @@ class WalletMigrationTest(BitcoinTestFramework): assert_equal(info["descriptors"], True) assert_equal(info["format"], "sqlite") + walletdir_list = wallet.listwalletdir() + assert {"name": info["walletname"]} in walletdir_list["wallets"] + # Check backup existence and its non-empty wallet filename - backup_path = self.nodes[0].wallets_path / f'default_wallet_{curr_time}.legacy.bak' + backup_filename = f"default_wallet_{curr_time}.legacy.bak" + backup_path = self.nodes[0].wallets_path / backup_filename assert backup_path.exists() assert_equal(str(backup_path), res['backup_path']) + assert {"name": backup_filename} not in walletdir_list["wallets"] def test_direct_file(self): self.log.info("Test migration of a wallet that is not in a wallet directory") @@ -1022,4 +1037,4 @@ class WalletMigrationTest(BitcoinTestFramework): self.test_blank() if __name__ == '__main__': - WalletMigrationTest().main() + WalletMigrationTest(__file__).main() diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py index 67e1283902..064eac499b 100755 --- a/test/functional/wallet_miniscript.py +++ b/test/functional/wallet_miniscript.py @@ -401,4 +401,4 @@ class WalletMiniscriptTest(BitcoinTestFramework): if __name__ == "__main__": - WalletMiniscriptTest().main() + WalletMiniscriptTest(__file__).main() diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py index 68bf45f7e3..2e0b0d1a41 100755 --- a/test/functional/wallet_multisig_descriptor_psbt.py +++ b/test/functional/wallet_multisig_descriptor_psbt.py @@ -7,7 +7,6 @@ This is meant to be documentation as much as functional tests, so it is kept as simple and readable as possible. """ -from test_framework.address import base58_to_byte from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_approx, @@ -30,10 +29,12 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): self.skip_if_no_sqlite() @staticmethod - def _get_xpub(wallet): + def _get_xpub(wallet, internal): """Extract the wallet's xpubs using `listdescriptors` and pick the one from the `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses).""" - descriptor = next(filter(lambda d: d["desc"].startswith("pkh"), wallet.listdescriptors()["descriptors"])) - return descriptor["desc"].split("]")[-1].split("/")[0] + pkh_descriptor = next(filter(lambda d: d["desc"].startswith("pkh(") and d["internal"] == internal, wallet.listdescriptors()["descriptors"])) + # Keep all key origin information (master key fingerprint and all derivation steps) for proper support of hardware devices + # See section 'Key origin identification' in 'doc/descriptors.md' for more details... + return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0] @staticmethod def _check_psbt(psbt, to, value, multisig): @@ -47,19 +48,13 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): amount += vout["value"] assert_approx(amount, float(value), vspan=0.001) - def participants_create_multisigs(self, xpubs): + def participants_create_multisigs(self, external_xpubs, internal_xpubs): """The multisig is created by importing the following descriptors. The resulting wallet is watch-only and every participant can do this.""" - # some simple validation - assert_equal(len(xpubs), self.N) - # a sanity-check/assertion, this will throw if the base58 checksum of any of the provided xpubs are invalid - for xpub in xpubs: - base58_to_byte(xpub) - for i, node in enumerate(self.nodes): node.createwallet(wallet_name=f"{self.name}_{i}", blank=True, descriptors=True, disable_private_keys=True) multisig = node.get_wallet_rpc(f"{self.name}_{i}") - external = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f'/0/*,'.join(xpubs)}/0/*))") - internal = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f'/1/*,'.join(xpubs)}/1/*))") + external = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f','.join(external_xpubs)}))") + internal = multisig.getdescriptorinfo(f"wsh(sortedmulti({self.M},{f','.join(internal_xpubs)}))") result = multisig.importdescriptors([ { # receiving addresses (internal: False) "desc": external["descriptor"], @@ -93,10 +88,10 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): } self.log.info("Generate and exchange xpubs...") - xpubs = [self._get_xpub(signer) for signer in participants["signers"]] + external_xpubs, internal_xpubs = [[self._get_xpub(signer, internal) for signer in participants["signers"]] for internal in [False, True]] self.log.info("Every participant imports the following descriptors to create the watch-only multisig...") - participants["multisigs"] = list(self.participants_create_multisigs(xpubs)) + participants["multisigs"] = list(self.participants_create_multisigs(external_xpubs, internal_xpubs)) self.log.info("Check that every participant's multisig generates the same addresses...") for _ in range(10): # we check that the first 10 generated addresses are the same for all participant's multisigs @@ -159,4 +154,4 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): if __name__ == "__main__": - WalletMultisigDescriptorPSBTTest().main() + WalletMultisigDescriptorPSBTTest(__file__).main() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index ee866ee59b..156f4279b4 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -423,4 +423,4 @@ class MultiWalletTest(BitcoinTestFramework): if __name__ == '__main__': - MultiWalletTest().main() + MultiWalletTest(__file__).main() diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py index 451f8abb0a..8a02781f26 100755 --- a/test/functional/wallet_orphanedreward.py +++ b/test/functional/wallet_orphanedreward.py @@ -73,4 +73,4 @@ class OrphanedBlockRewardTest(BitcoinTestFramework): if __name__ == '__main__': - OrphanedBlockRewardTest().main() + OrphanedBlockRewardTest(__file__).main() diff --git a/test/functional/wallet_pruning.py b/test/functional/wallet_pruning.py index 6e252b5406..9c34a24be9 100755 --- a/test/functional/wallet_pruning.py +++ b/test/functional/wallet_pruning.py @@ -155,4 +155,4 @@ class WalletPruningTest(BitcoinTestFramework): self.test_wallet_import_pruned_with_missing_blocks(wallet_birthheight_1) if __name__ == '__main__': - WalletPruningTest().main() + WalletPruningTest(__file__).main() diff --git a/test/functional/wallet_reindex.py b/test/functional/wallet_reindex.py index 5388de4b71..6778f76efc 100755 --- a/test/functional/wallet_reindex.py +++ b/test/functional/wallet_reindex.py @@ -105,4 +105,4 @@ class WalletReindexTest(BitcoinTestFramework): if __name__ == '__main__': - WalletReindexTest().main() + WalletReindexTest(__file__).main() diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py index 4271f3e481..77cf34898b 100755 --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -101,4 +101,4 @@ class ReorgsRestoreTest(BitcoinTestFramework): assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"] if __name__ == '__main__': - ReorgsRestoreTest().main() + ReorgsRestoreTest(__file__).main() diff --git a/test/functional/wallet_rescan_unconfirmed.py b/test/functional/wallet_rescan_unconfirmed.py index ad9fa081c2..69ad522b5d 100755 --- a/test/functional/wallet_rescan_unconfirmed.py +++ b/test/functional/wallet_rescan_unconfirmed.py @@ -80,4 +80,4 @@ class WalletRescanUnconfirmed(BitcoinTestFramework): assert_equal(w1.gettransaction(tx_child_unconfirmed_sweep["txid"])["confirmations"], 0) if __name__ == '__main__': - WalletRescanUnconfirmed().main() + WalletRescanUnconfirmed(__file__).main() diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index f61e1edc1d..49c8ef1c5f 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -149,4 +149,4 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): if __name__ == '__main__': - ResendWalletTransactionsTest().main() + ResendWalletTransactionsTest(__file__).main() diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index bbb0d658d9..2d0aad3b5d 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -612,4 +612,4 @@ class WalletSendTest(BitcoinTestFramework): if __name__ == '__main__': - WalletSendTest().main() + WalletSendTest(__file__).main() diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py index 1d308c225d..b256b53b38 100755 --- a/test/functional/wallet_sendall.py +++ b/test/functional/wallet_sendall.py @@ -531,4 +531,4 @@ class SendallTest(BitcoinTestFramework): self.sendall_fails_with_transaction_too_large() if __name__ == '__main__': - SendallTest().main() + SendallTest(__file__).main() diff --git a/test/functional/wallet_sendmany.py b/test/functional/wallet_sendmany.py index 5751993143..ad99100590 100755 --- a/test/functional/wallet_sendmany.py +++ b/test/functional/wallet_sendmany.py @@ -40,4 +40,4 @@ class SendmanyTest(BitcoinTestFramework): if __name__ == '__main__': - SendmanyTest().main() + SendmanyTest(__file__).main() diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py index abfc3c1ba1..52b4c390b8 100755 --- a/test/functional/wallet_signer.py +++ b/test/functional/wallet_signer.py @@ -263,4 +263,4 @@ class WalletSignerTest(BitcoinTestFramework): assert_raises_rpc_error(-1, "GetExternalSigner: More than one external signer found", self.nodes[1].createwallet, wallet_name='multi_hww', disable_private_keys=True, descriptors=True, external_signer=True) if __name__ == '__main__': - WalletSignerTest().main() + WalletSignerTest(__file__).main() diff --git a/test/functional/wallet_signmessagewithaddress.py b/test/functional/wallet_signmessagewithaddress.py index 4a4b818bd1..170c883ca4 100755 --- a/test/functional/wallet_signmessagewithaddress.py +++ b/test/functional/wallet_signmessagewithaddress.py @@ -45,4 +45,4 @@ class SignMessagesWithAddressTest(BitcoinTestFramework): if __name__ == '__main__': - SignMessagesWithAddressTest().main() + SignMessagesWithAddressTest(__file__).main() diff --git a/test/functional/wallet_signrawtransactionwithwallet.py b/test/functional/wallet_signrawtransactionwithwallet.py index 612a2542e7..eb0e4097fe 100755 --- a/test/functional/wallet_signrawtransactionwithwallet.py +++ b/test/functional/wallet_signrawtransactionwithwallet.py @@ -310,4 +310,4 @@ class SignRawTransactionWithWalletTest(BitcoinTestFramework): if __name__ == '__main__': - SignRawTransactionWithWalletTest().main() + SignRawTransactionWithWalletTest(__file__).main() diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py index 545aad892c..11b7a4c76e 100755 --- a/test/functional/wallet_simulaterawtx.py +++ b/test/functional/wallet_simulaterawtx.py @@ -129,4 +129,4 @@ class SimulateTxTest(BitcoinTestFramework): assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w2.simulaterawtransaction, [tx1, tx2]) if __name__ == '__main__': - SimulateTxTest().main() + SimulateTxTest(__file__).main() diff --git a/test/functional/wallet_spend_unconfirmed.py b/test/functional/wallet_spend_unconfirmed.py index bfcdeaeaa8..4c73e0970b 100755 --- a/test/functional/wallet_spend_unconfirmed.py +++ b/test/functional/wallet_spend_unconfirmed.py @@ -505,4 +505,4 @@ class UnconfirmedInputTest(BitcoinTestFramework): self.test_external_input_unconfirmed_low() if __name__ == '__main__': - UnconfirmedInputTest().main() + UnconfirmedInputTest(__file__).main() diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py index 2cc4e312af..6feb00af8e 100755 --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -58,4 +58,4 @@ class WalletStartupTest(BitcoinTestFramework): assert_equal(set(self.nodes[0].listwallets()), set(('w2', 'w3'))) if __name__ == '__main__': - WalletStartupTest().main() + WalletStartupTest(__file__).main() diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py index a5d7445ce8..a88d84f4c6 100755 --- a/test/functional/wallet_taproot.py +++ b/test/functional/wallet_taproot.py @@ -507,4 +507,4 @@ class WalletTaprootTest(BitcoinTestFramework): ) if __name__ == '__main__': - WalletTaprootTest().main() + WalletTaprootTest(__file__).main() diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py index 0a622979a4..6c88438330 100755 --- a/test/functional/wallet_timelock.py +++ b/test/functional/wallet_timelock.py @@ -50,4 +50,4 @@ class WalletLocktimeTest(BitcoinTestFramework): if __name__ == "__main__": - WalletLocktimeTest().main() + WalletLocktimeTest(__file__).main() diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py index ea99992084..fb6dc74dc5 100755 --- a/test/functional/wallet_transactiontime_rescan.py +++ b/test/functional/wallet_transactiontime_rescan.py @@ -223,4 +223,4 @@ class TransactionTimeRescanTest(BitcoinTestFramework): assert_equal(encrypted_wallet.getbalance(), temp_wallet.getbalance()) if __name__ == '__main__': - TransactionTimeRescanTest().main() + TransactionTimeRescanTest(__file__).main() diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 1f3b6f2ce9..a2dd223aed 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -149,4 +149,4 @@ class TxnMallTest(BitcoinTestFramework): if __name__ == '__main__': - TxnMallTest().main() + TxnMallTest(__file__).main() diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index 3cd0cd3207..3d6830f1f3 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -138,4 +138,4 @@ class TxnMallTest(BitcoinTestFramework): if __name__ == '__main__': - TxnMallTest().main() + TxnMallTest(__file__).main() diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index a4f2a9b74d..7d1d244dff 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -360,4 +360,4 @@ class UpgradeWalletTest(BitcoinTestFramework): self.test_upgradewallet(disabled_wallet, previous_version=169900, expected_version=169900) if __name__ == '__main__': - UpgradeWalletTest().main() + UpgradeWalletTest(__file__).main() diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py index b473f5d65c..298d50d452 100755 --- a/test/functional/wallet_watchonly.py +++ b/test/functional/wallet_watchonly.py @@ -111,4 +111,4 @@ class CreateWalletWatchonlyTest(BitcoinTestFramework): if __name__ == '__main__': - CreateWalletWatchonlyTest().main() + CreateWalletWatchonlyTest(__file__).main() diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py index d9f86b22b8..5d01b13fd4 100755 --- a/test/lint/lint-assertions.py +++ b/test/lint/lint-assertions.py @@ -27,8 +27,9 @@ def main(): # checks should be used over assert. See: src/util/check.h # src/rpc/server.cpp is excluded from this check since it's mostly meta-code. exit_code = git_grep([ - "-nE", - r"\<(A|a)ss(ume|ert) *\(.*\);", + "--line-number", + "--extended-regexp", + r"\<(A|a)ss(ume|ert)\(", "--", "src/rpc/", "src/wallet/rpc*", @@ -38,8 +39,9 @@ def main(): # The `BOOST_ASSERT` macro requires to `#include boost/assert.hpp`, # which is an unnecessary Boost dependency. exit_code |= git_grep([ - "-E", - r"BOOST_ASSERT *\(.*\);", + "--line-number", + "--extended-regexp", + r"BOOST_ASSERT\(", "--", "*.cpp", "*.h", diff --git a/test/lint/lint-python-mutable-default-parameters.py b/test/lint/lint-python-mutable-default-parameters.py deleted file mode 100755 index 820595ea34..0000000000 --- a/test/lint/lint-python-mutable-default-parameters.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -# -# 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. - -""" -Detect when a mutable list or dict is used as a default parameter value in a Python function. -""" - -import subprocess -import sys - - -def main(): - command = [ - "git", - "grep", - "-E", - r"^\s*def [a-zA-Z0-9_]+\(.*=\s*(\[|\{)", - "--", - "*.py", - ] - 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" - f"{output.stdout}\n" - f"{example()}" - ) - print(error_msg) - sys.exit(1) - else: - sys.exit(0) - - -def example(): - return """This is how mutable list and dict default parameter values behave: - ->>> def f(i, j=[], k={}): -... j.append(i) -... k[i] = True -... return j, k -... ->>> f(1) -([1], {1: True}) ->>> f(1) -([1, 1], {1: True}) ->>> f(2) -([1, 1, 2], {1: True, 2: True}) - -The intended behaviour was likely: - ->>> def f(i, j=None, k=None): -... if j is None: -... j = [] -... if k is None: -... k = {} -... j.append(i) -... k[i] = True -... return j, k -... ->>> f(1) -([1], {1: True}) ->>> f(1) -([1], {1: True}) ->>> f(2) -([2], {2: True})""" - - -if __name__ == "__main__": - main() diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt index cb0e0c4d31..ef7d906d78 100644 --- a/test/lint/spelling.ignore-words.txt +++ b/test/lint/spelling.ignore-words.txt @@ -1,4 +1,5 @@ afile +amountIn asend ba blockin @@ -7,8 +8,10 @@ cachable clen crypted debbugs +deques fo fpr +hashIn hights inflight invokable @@ -17,6 +20,7 @@ lief mor nd nin +outIn requestor ser siz @@ -24,5 +28,6 @@ stap unparseable unser useable +viewIn warmup wit diff --git a/test/lint/test_runner/src/main.rs b/test/lint/test_runner/src/main.rs index 9c35898c1f..77388b78ff 100644 --- a/test/lint/test_runner/src/main.rs +++ b/test/lint/test_runner/src/main.rs @@ -36,6 +36,11 @@ fn get_linter_list() -> Vec<&'static Linter> { lint_fn: lint_markdown }, &Linter { + description: "Check the default arguments in python", + name: "py_mut_arg_default", + lint_fn: lint_py_mut_arg_default, + }, + &Linter { description: "Check that std::filesystem is not used directly", name: "std_filesystem", lint_fn: lint_std_filesystem @@ -180,6 +185,35 @@ fn lint_subtree() -> LintResult { } } +fn lint_py_mut_arg_default() -> LintResult { + let bin_name = "ruff"; + let checks = ["B006", "B008"] + .iter() + .map(|c| format!("--select={}", c)) + .collect::<Vec<_>>(); + let files = check_output( + git() + .args(["ls-files", "--", "*.py"]) + .args(get_pathspecs_exclude_subtrees()), + )?; + + let mut cmd = Command::new(bin_name); + cmd.arg("check").args(checks).args(files.lines()); + + match cmd.status() { + Ok(status) if status.success() => Ok(()), + Ok(_) => Err(format!("`{}` found errors!", bin_name)), + Err(e) if e.kind() == ErrorKind::NotFound => { + println!( + "`{}` was not found in $PATH, skipping those checks.", + bin_name + ); + Ok(()) + } + Err(e) => Err(format!("Error running `{}`: {}", bin_name, e)), + } +} + fn lint_std_filesystem() -> LintResult { let found = git() .args([ @@ -410,6 +444,7 @@ fn lint_markdown() -> LintResult { "--offline", "--ignore-path", md_ignore_path_str.as_str(), + "--gitignore", "--root-dir", ".", ]) @@ -419,11 +454,6 @@ fn lint_markdown() -> LintResult { Ok(output) if output.status.success() => Ok(()), Ok(output) => { let stderr = String::from_utf8_lossy(&output.stderr); - let filtered_stderr: String = stderr // Filter out this annoying trailing line - .lines() - .filter(|&line| line != "The following links could not be resolved:") - .collect::<Vec<&str>>() - .join("\n"); Err(format!( r#" One or more markdown links are broken. @@ -433,7 +463,7 @@ Relative links are preferred (but not required) as jumping to file works nativel Markdown link errors found: {} "#, - filtered_stderr + stderr )) } Err(e) if e.kind() == ErrorKind::NotFound => { diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 65effa7a27..94bd14e6c3 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -56,7 +56,8 @@ unsigned-integer-overflow:CBlockPolicyEstimator::processBlockTx unsigned-integer-overflow:TxConfirmStats::EstimateMedianVal unsigned-integer-overflow:prevector.h unsigned-integer-overflow:EvalScript -unsigned-integer-overflow:xoroshiro128plusplus.h +unsigned-integer-overflow:InsecureRandomContext::rand64 +unsigned-integer-overflow:InsecureRandomContext::SplitMix64 unsigned-integer-overflow:bitset_detail::PopCount implicit-integer-sign-change:CBlockPolicyEstimator::processBlockTx implicit-integer-sign-change:SetStdinEcho @@ -73,4 +74,6 @@ shift-base:arith_uint256.cpp shift-base:crypto/ shift-base:streams.h shift-base:FormatHDKeypath -shift-base:xoroshiro128plusplus.h +shift-base:InsecureRandomContext::rand64 +shift-base:RandomMixin<*>::randbits +shift-base:RandomMixin<*>::randbits<*> |